goscript 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/compiler/gotest/runner.go +98 -0
  2. package/compiler/gotest/runner_test.go +45 -0
  3. package/compiler/gotest/testdata/browserapi/browserapi_test.go +36 -0
  4. package/compiler/lowering.go +227 -11
  5. package/compiler/override-registry_test.go +50 -0
  6. package/compiler/protobuf-ts-binding.go +155 -7
  7. package/compiler/protobuf-ts-binding_test.go +116 -2
  8. package/compiler/runtime-contract.go +2 -0
  9. package/compiler/runtime-contract_test.go +1 -0
  10. package/compiler/semantic-model.go +16 -0
  11. package/compiler/semantic-model_test.go +38 -0
  12. package/compiler/skeleton_test.go +477 -16
  13. package/compiler/typescript-emitter.go +4 -0
  14. package/dist/gs/builtin/builtin.js +7 -9
  15. package/dist/gs/builtin/builtin.js.map +1 -1
  16. package/dist/gs/builtin/defer.js +2 -2
  17. package/dist/gs/builtin/hostio.js +5 -5
  18. package/dist/gs/builtin/hostio.js.map +1 -1
  19. package/dist/gs/builtin/map.js +2 -1
  20. package/dist/gs/builtin/map.js.map +1 -1
  21. package/dist/gs/builtin/slice.d.ts +3 -0
  22. package/dist/gs/builtin/slice.js +39 -0
  23. package/dist/gs/builtin/slice.js.map +1 -1
  24. package/dist/gs/builtin/type.js +49 -0
  25. package/dist/gs/builtin/type.js.map +1 -1
  26. package/dist/gs/compress/zlib/index.js +5 -2
  27. package/dist/gs/compress/zlib/index.js.map +1 -1
  28. package/dist/gs/crypto/aes/index.d.ts +15 -0
  29. package/dist/gs/crypto/aes/index.js +57 -0
  30. package/dist/gs/crypto/aes/index.js.map +1 -0
  31. package/dist/gs/crypto/cipher/index.d.ts +41 -0
  32. package/dist/gs/crypto/cipher/index.js +255 -0
  33. package/dist/gs/crypto/cipher/index.js.map +1 -0
  34. package/dist/gs/crypto/ecdh/index.js +27 -8
  35. package/dist/gs/crypto/ecdh/index.js.map +1 -1
  36. package/dist/gs/crypto/ed25519/index.js +3 -3
  37. package/dist/gs/crypto/ed25519/index.js.map +1 -1
  38. package/dist/gs/crypto/rand/index.js +6 -3
  39. package/dist/gs/crypto/rand/index.js.map +1 -1
  40. package/dist/gs/embed/index.js +9 -3
  41. package/dist/gs/embed/index.js.map +1 -1
  42. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.d.ts +1 -0
  43. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js +33 -0
  44. package/dist/gs/github.com/aperturerobotics/protobuf-go-lite/index.js.map +1 -1
  45. package/dist/gs/github.com/mr-tron/base58/base58/index.js +4 -1
  46. package/dist/gs/github.com/mr-tron/base58/base58/index.js.map +1 -1
  47. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.d.ts +31 -0
  48. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js +117 -0
  49. package/dist/gs/golang.org/x/crypto/chacha20poly1305/index.js.map +1 -0
  50. package/dist/gs/golang.org/x/crypto/scrypt/index.d.ts +2 -0
  51. package/dist/gs/golang.org/x/crypto/scrypt/index.js +39 -0
  52. package/dist/gs/golang.org/x/crypto/scrypt/index.js.map +1 -0
  53. package/dist/gs/hash/fnv/index.js +13 -5
  54. package/dist/gs/hash/fnv/index.js.map +1 -1
  55. package/dist/gs/io/fs/glob.d.ts +3 -3
  56. package/dist/gs/io/fs/glob.js +8 -8
  57. package/dist/gs/io/fs/glob.js.map +1 -1
  58. package/dist/gs/io/fs/readdir.d.ts +2 -2
  59. package/dist/gs/io/fs/readdir.js +13 -74
  60. package/dist/gs/io/fs/readdir.js.map +1 -1
  61. package/dist/gs/io/fs/sub.js +4 -4
  62. package/dist/gs/io/fs/sub.js.map +1 -1
  63. package/dist/gs/io/fs/walk.js +1 -1
  64. package/dist/gs/io/fs/walk.js.map +1 -1
  65. package/dist/gs/io/io.js +18 -2
  66. package/dist/gs/io/io.js.map +1 -1
  67. package/dist/gs/maps/iter.js.map +1 -1
  68. package/dist/gs/maps/maps.js.map +1 -1
  69. package/dist/gs/mime/index.js +5 -2
  70. package/dist/gs/mime/index.js.map +1 -1
  71. package/dist/gs/net/http/httptest/index.js +6 -3
  72. package/dist/gs/net/http/httptest/index.js.map +1 -1
  73. package/dist/gs/net/http/index.d.ts +16 -4
  74. package/dist/gs/net/http/index.js +236 -40
  75. package/dist/gs/net/http/index.js.map +1 -1
  76. package/dist/gs/net/http/pprof/index.js.map +1 -1
  77. package/dist/gs/reflect/iter.js +1 -1
  78. package/dist/gs/reflect/iter.js.map +1 -1
  79. package/dist/gs/reflect/type.d.ts +2 -0
  80. package/dist/gs/reflect/type.js +53 -21
  81. package/dist/gs/reflect/type.js.map +1 -1
  82. package/dist/gs/runtime/debug/index.js +2 -1
  83. package/dist/gs/runtime/debug/index.js.map +1 -1
  84. package/dist/gs/runtime/pprof/index.js.map +1 -1
  85. package/dist/gs/runtime/runtime.js +2 -2
  86. package/dist/gs/runtime/runtime.js.map +1 -1
  87. package/dist/gs/runtime/trace/index.js.map +1 -1
  88. package/dist/gs/slices/slices.d.ts +1 -1
  89. package/dist/gs/slices/slices.js +37 -4
  90. package/dist/gs/slices/slices.js.map +1 -1
  91. package/go.mod +2 -2
  92. package/go.sum +2 -0
  93. package/gs/builtin/builtin.ts +11 -14
  94. package/gs/builtin/defer.ts +2 -2
  95. package/gs/builtin/hostio.test.ts +8 -3
  96. package/gs/builtin/hostio.ts +5 -7
  97. package/gs/builtin/map.ts +4 -1
  98. package/gs/builtin/slice.test.ts +14 -0
  99. package/gs/builtin/slice.ts +64 -0
  100. package/gs/builtin/type.ts +72 -0
  101. package/gs/bytes/bytes.test.ts +14 -13
  102. package/gs/compress/zlib/index.test.ts +19 -5
  103. package/gs/compress/zlib/index.ts +16 -7
  104. package/gs/context/context.test.ts +3 -1
  105. package/gs/crypto/aes/index.test.ts +120 -0
  106. package/gs/crypto/aes/index.ts +76 -0
  107. package/gs/crypto/cipher/index.ts +345 -0
  108. package/gs/crypto/cipher/meta.json +6 -0
  109. package/gs/crypto/ecdh/index.test.ts +6 -2
  110. package/gs/crypto/ecdh/index.ts +49 -12
  111. package/gs/crypto/ed25519/index.ts +20 -7
  112. package/gs/crypto/rand/index.ts +6 -3
  113. package/gs/embed/index.test.ts +3 -3
  114. package/gs/embed/index.ts +9 -3
  115. package/gs/fmt/fmt.test.ts +29 -4
  116. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.test.ts +126 -0
  117. package/gs/github.com/aperturerobotics/protobuf-go-lite/index.ts +46 -0
  118. package/gs/github.com/mr-tron/base58/base58/index.ts +9 -3
  119. package/gs/github.com/zeebo/blake3/internal/consts/index.test.ts +2 -8
  120. package/gs/golang.org/x/crypto/chacha20poly1305/index.test.ts +91 -0
  121. package/gs/golang.org/x/crypto/chacha20poly1305/index.ts +245 -0
  122. package/gs/golang.org/x/crypto/scrypt/index.test.ts +81 -0
  123. package/gs/golang.org/x/crypto/scrypt/index.ts +54 -0
  124. package/gs/golang.org/x/crypto/scrypt/meta.json +5 -0
  125. package/gs/hash/fnv/index.test.ts +1 -8
  126. package/gs/hash/fnv/index.ts +27 -10
  127. package/gs/io/fs/glob.ts +13 -10
  128. package/gs/io/fs/meta.json +2 -0
  129. package/gs/io/fs/readdir.test.ts +63 -2
  130. package/gs/io/fs/readdir.ts +33 -30
  131. package/gs/io/fs/sub.ts +4 -4
  132. package/gs/io/fs/walk.ts +1 -1
  133. package/gs/io/io.test.ts +56 -1
  134. package/gs/io/io.ts +19 -2
  135. package/gs/maps/iter.ts +9 -9
  136. package/gs/maps/maps.ts +4 -4
  137. package/gs/math/bits/index.test.ts +10 -1
  138. package/gs/mime/index.test.ts +33 -15
  139. package/gs/mime/index.ts +9 -2
  140. package/gs/net/http/httptest/index.test.ts +17 -3
  141. package/gs/net/http/httptest/index.ts +8 -3
  142. package/gs/net/http/index.test.ts +645 -123
  143. package/gs/net/http/index.ts +548 -113
  144. package/gs/net/http/pprof/index.ts +24 -6
  145. package/gs/os/file_unix_js.test.ts +22 -0
  146. package/gs/reflect/iter.ts +4 -2
  147. package/gs/reflect/map.test.ts +56 -1
  148. package/gs/reflect/type.ts +76 -37
  149. package/gs/runtime/debug/index.test.ts +32 -4
  150. package/gs/runtime/debug/index.ts +5 -2
  151. package/gs/runtime/pprof/index.test.ts +7 -1
  152. package/gs/runtime/pprof/index.ts +5 -1
  153. package/gs/runtime/runtime.test.ts +7 -0
  154. package/gs/runtime/runtime.ts +2 -4
  155. package/gs/runtime/trace/index.test.ts +9 -1
  156. package/gs/runtime/trace/index.ts +5 -1
  157. package/gs/slices/meta.json +3 -0
  158. package/gs/slices/slices.test.ts +59 -21
  159. package/gs/slices/slices.ts +61 -20
  160. package/gs/strconv/complex.test.ts +17 -3
  161. package/gs/sync/atomic/doc_64.test.ts +2 -9
  162. package/gs/sync/sync.test.ts +18 -8
  163. package/gs/syscall/js/index.test.ts +9 -4
  164. package/package.json +13 -5
@@ -1541,6 +1541,9 @@ func TestCompilePackagesLowersUnsafeBytePointerArithmetic(t *testing.T) {
1541
1541
  if !strings.Contains(text, "$.arrayPointerFromIndexRef<number>($.indexRef($.pointerValue<number[]>(words), 0), 64, 4, 1)") {
1542
1542
  t.Fatalf("missing byte-view array pointer conversion:\n%s", text)
1543
1543
  }
1544
+ if !strings.Contains(text, "($.arrayPointerFromIndexRef<number>($.indexRef(dst!, 0), 64, 1, 1) as unknown as $.VarRef<Uint8Array> | null)!.value =") {
1545
+ t.Fatalf("missing non-null byte-view array pointer storage:\n%s", text)
1546
+ }
1544
1547
  }
1545
1548
 
1546
1549
  func TestCompilePackagesEmitsStructMethodsAndPointerAssertions(t *testing.T) {
@@ -2488,7 +2491,7 @@ func TestCompilePackagesAssertsInterfaceMethodReceivers(t *testing.T) {
2488
2491
  text := string(content)
2489
2492
  for _, want := range []string{
2490
2493
  "export type FileInfo = {",
2491
- "$.println($.pointerValue<Exclude<FileInfo, null>>(info).Name())",
2494
+ "$.println(await $.pointerValue<Exclude<FileInfo, null>>(info).Name())",
2492
2495
  } {
2493
2496
  if !strings.Contains(text, want) {
2494
2497
  t.Fatalf("missing %q in generated output:\n%s", want, text)
@@ -2590,7 +2593,7 @@ func TestCompilePackagesBoxesTypedNilInterfaceValues(t *testing.T) {
2590
2593
  text := string(content)
2591
2594
  for _, want := range []string{
2592
2595
  "return $.interfaceValue<Animal | null>(FindDog(), \"*main.Dog\")",
2593
- "$.println($.pointerValue<Exclude<Animal, null>>(animal).Name())",
2596
+ "$.println(await $.pointerValue<Exclude<Animal, null>>(animal).Name())",
2594
2597
  "let a: Animal | null = $.interfaceValue<Animal | null>(dog, \"*main.Dog\")",
2595
2598
  } {
2596
2599
  if !strings.Contains(text, want) {
@@ -2697,16 +2700,16 @@ func TestCompilePackagesEmitsGenericMethodsAliasesAndDictionaries(t *testing.T)
2697
2700
  "public Get(): any",
2698
2701
  "export function NewBox(__typeArgs: $.GenericTypeArgs | undefined, value: any): Box",
2699
2702
  "export function ZeroValue(__typeArgs: $.GenericTypeArgs | undefined): any",
2700
- "export function CallString(__typeArgs: $.GenericTypeArgs | undefined, v: any): string",
2703
+ "export async function CallString(__typeArgs: $.GenericTypeArgs | undefined, v: any): globalThis.Promise<string>",
2701
2704
  "export function Sum<T>(__typeArgs: $.GenericTypeArgs | undefined, vals: $.Slice<T>): any",
2702
2705
  "export function Copy<T>(__typeArgs: $.GenericTypeArgs | undefined, vals: $.Slice<T>): $.Slice<T>",
2703
- "return $.append($.arrayToSlice<T>([]), ...(vals ?? []))",
2706
+ "return $.appendSlice($.arrayToSlice<T>([]), vals)",
2704
2707
  "let seen: Set = $.makeMap<number, {}>()",
2705
2708
  "$.mapSet(seen, 1, {})",
2706
2709
  "$.genericZero(__typeArgs, \"T\", null)",
2707
- "$.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
2710
+ "await $.callGenericMethod(__typeArgs, \"T\", \"String\", v)",
2708
2711
  "ZeroValue({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }})",
2709
- "CallString({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }}, zero)",
2712
+ "await CallString({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }}, zero)",
2710
2713
  "Sum({T: { type: { kind: $.TypeKind.Basic, name: \"int\", typeName: \"main.MyInt\" }, zero: () => 0, methods: {String: (receiver: any, ...args: any[]) => (MyInt_String as any)(($.isVarRef(receiver) ? receiver.value : receiver), ...args)}, methodSignatures: [{ name: \"String\", args: [], returns: [{ name: \"_r0\", type: { kind: $.TypeKind.Basic, name: \"string\" } }] }] }}, null)",
2711
2714
  } {
2712
2715
  if !strings.Contains(text, want) {
@@ -2737,11 +2740,17 @@ func TestCompilePackagesInfersGenericTypeArgsFromNamedArgument(t *testing.T) {
2737
2740
  " f := entries[key.name].factory",
2738
2741
  " return f.(func() T)()",
2739
2742
  "}",
2743
+ "type typedLoader[T any] struct { value T }",
2744
+ "func (t *typedLoader[T]) Load() T { return t.value }",
2745
+ "func GetTyped[T any](v any) T {",
2746
+ " src := v.(interface { Load() T })",
2747
+ " return src.Load()",
2748
+ "}",
2740
2749
  "var loader = NewKey[Source](\"source\")",
2741
2750
  "func Use() int {",
2742
2751
  " Register(loader, func() Source { return &auto{} })",
2743
2752
  " src := Get(loader)",
2744
- " return src.Load()",
2753
+ " return src.Load() + GetTyped[int](&typedLoader[int]{value: 5})",
2745
2754
  "}",
2746
2755
  "",
2747
2756
  }, "\n"),
@@ -2763,8 +2772,9 @@ func TestCompilePackagesInfersGenericTypeArgsFromNamedArgument(t *testing.T) {
2763
2772
  text := string(content)
2764
2773
  for _, want := range []string{
2765
2774
  "await Get({T: { type: \"genericnamedarg.Source\", zero: () => null, methods: {Load: (receiver: any, ...args: any[]) => receiver.Load(...args)} }}, $.markAsStructValue($.cloneStructValue(loader)))",
2766
- "return await $.mustTypeAssert<(() => any | globalThis.Promise<any>) | null>(f, ({ kind: $.TypeKind.Function, params: [], results: [{ kind: $.TypeKind.Interface, methods: [] }] } as $.FunctionTypeInfo))!()",
2767
- "return $.pointerValue<Exclude<Source, null>>(src).Load()",
2775
+ "return await $.mustTypeAssert<(() => any | globalThis.Promise<any>) | null>(f, ({ kind: $.TypeKind.Function, params: [], results: [__typeArgs?.[\"T\"]?.type ?? { kind: $.TypeKind.Interface, methods: [] }] } as $.FunctionTypeInfo))!()",
2776
+ "$.mustTypeAssert<any>(v, { kind: $.TypeKind.Interface, methods: [{ name: \"Load\", args: [], returns: [{ name: \"_r0\", type: __typeArgs?.[\"T\"]?.type ?? { kind: $.TypeKind.Interface, methods: [] } }] }] })",
2777
+ "return await $.pointerValue<Exclude<Source, null>>(src).Load()",
2768
2778
  } {
2769
2779
  if !strings.Contains(text, want) {
2770
2780
  t.Fatalf("missing %q in generated output:\n%s", want, text)
@@ -3051,12 +3061,16 @@ func TestCompilePackagesAwaitsFmtWriterOverrides(t *testing.T) {
3051
3061
  for _, want := range []string{
3052
3062
  "export async function Use",
3053
3063
  "await fmt.Fprintf(",
3064
+ "$.pointerValue<writer>(w).buf = $.appendSlice($.pointerValue<writer>(w).buf, p)",
3054
3065
  "return err",
3055
3066
  } {
3056
3067
  if !strings.Contains(text, want) {
3057
3068
  t.Fatalf("missing %q in generated output:\n%s", want, text)
3058
3069
  }
3059
3070
  }
3071
+ if strings.Contains(text, "...(p ?? [])") {
3072
+ t.Fatalf("append with slice expansion used JavaScript argument spreading:\n%s", text)
3073
+ }
3060
3074
  }
3061
3075
 
3062
3076
  func TestCompilePackagesImportsSelectedExternalFieldTypes(t *testing.T) {
@@ -3436,7 +3450,7 @@ func TestCompilePackagesEmitsAsyncChannelsSelectAndDefer(t *testing.T) {
3436
3450
  for _, want := range []string{
3437
3451
  "Process(v: number): number | globalThis.Promise<number>",
3438
3452
  "public async Process(v: number): globalThis.Promise<number>",
3439
- "let ch = $.makeChannel<number>(1, 0, \"both\")",
3453
+ "let ch: $.Channel<number> | null = $.makeChannel<number>(1, 0, \"both\")",
3440
3454
  "await $.chanSend($.pointerValue<Worker>(w).ch, v)",
3441
3455
  "return await $.chanRecv($.pointerValue<Worker>(w).ch)",
3442
3456
  "await using __defer = new $.AsyncDisposableStack()",
@@ -3610,7 +3624,7 @@ func TestCompilePackagesPropagatesAsyncThroughInstantiatedNamedInterface(t *test
3610
3624
  }
3611
3625
  }
3612
3626
 
3613
- func TestCompilePackagesDoesNotAwaitUnmarkedAnonymousInterfaceMethod(t *testing.T) {
3627
+ func TestCompilePackagesAwaitsUnmarkedAnonymousInterfaceMethodInsideAsyncCaller(t *testing.T) {
3614
3628
  moduleDir := writePackageGraphFixture(t, map[string]string{
3615
3629
  "go.mod": "module example.test/anonymousifaceawait\n\ngo 1.25.3\n",
3616
3630
  "main.go": strings.Join([]string{
@@ -3644,8 +3658,8 @@ func TestCompilePackagesDoesNotAwaitUnmarkedAnonymousInterfaceMethod(t *testing.
3644
3658
  t.Fatal(err.Error())
3645
3659
  }
3646
3660
  text := string(content)
3647
- if strings.Contains(text, "return await $.pointerValue<any>(w).WaitValueChange(ctx, old, null)") {
3648
- t.Fatalf("anonymous interface method call without an async implementation was awaited:\n%s", text)
3661
+ if !strings.Contains(text, "return await $.pointerValue<any>(w).WaitValueChange(ctx, old, null)") {
3662
+ t.Fatalf("anonymous interface method call inside async caller was not awaited:\n%s", text)
3649
3663
  }
3650
3664
  }
3651
3665
 
@@ -3654,7 +3668,8 @@ func TestCompilePackagesDoesNotInheritAsyncIntoSyncFunctionLiteral(t *testing.T)
3654
3668
  "go.mod": "module example.test/syncfunclit\n\ngo 1.25.3\n",
3655
3669
  "main.go": strings.Join([]string{
3656
3670
  "package syncfunclit",
3657
- "type Directive interface{ GetDirective() any }",
3671
+ "type Directive struct{}",
3672
+ "func (Directive) GetDirective() any { return nil }",
3658
3673
  "type Bridge struct{ keep func(Directive) (bool, error) }",
3659
3674
  "func NewBridge(keep func(Directive) (bool, error)) *Bridge { return &Bridge{keep: keep} }",
3660
3675
  "func Execute(ch <-chan struct{}) error {",
@@ -3688,11 +3703,103 @@ func TestCompilePackagesDoesNotInheritAsyncIntoSyncFunctionLiteral(t *testing.T)
3688
3703
  t.Fatal(err.Error())
3689
3704
  }
3690
3705
  text := string(content)
3691
- if strings.Contains(text, "await $.pointerValue<Exclude<Directive, null>>(di).GetDirective()") {
3706
+ if strings.Contains(text, "await Directive.prototype.GetDirective.call(di)") {
3692
3707
  t.Fatalf("sync function literal inherited async await:\n%s", text)
3693
3708
  }
3694
3709
  }
3695
3710
 
3711
+ func TestCompilePackagesMarksFunctionLiteralAsyncForInterfaceMethodCall(t *testing.T) {
3712
+ moduleDir := writePackageGraphFixture(t, map[string]string{
3713
+ "go.mod": "module example.test/funclitifaceawait\n\ngo 1.25.3\n",
3714
+ "main.go": strings.Join([]string{
3715
+ "package funclitifaceawait",
3716
+ "type Ref struct{}",
3717
+ "type BlockWithRefs interface {",
3718
+ " ApplyBlockRef(uint32, *Ref) error",
3719
+ "}",
3720
+ "func Each(cb func(BlockWithRefs) error) error { return nil }",
3721
+ "func Copy(ref *Ref) error {",
3722
+ " return Each(func(block BlockWithRefs) error {",
3723
+ " if err := block.ApplyBlockRef(7, ref); err != nil {",
3724
+ " return err",
3725
+ " }",
3726
+ " return nil",
3727
+ " })",
3728
+ "}",
3729
+ "",
3730
+ }, "\n"),
3731
+ })
3732
+ outputDir := filepath.Join(t.TempDir(), "output")
3733
+ comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
3734
+ if err != nil {
3735
+ t.Fatal(err.Error())
3736
+ }
3737
+
3738
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
3739
+ t.Fatal(err.Error())
3740
+ }
3741
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "funclitifaceawait", "main.gs.ts")
3742
+ content, err := os.ReadFile(outputFile)
3743
+ if err != nil {
3744
+ t.Fatal(err.Error())
3745
+ }
3746
+ text := string(content)
3747
+ for _, want := range []string{
3748
+ "$.functionValue(async (block: BlockWithRefs | null): globalThis.Promise<$.GoError> => {",
3749
+ "let err = await $.pointerValue<Exclude<BlockWithRefs, null>>(block).ApplyBlockRef($.uint(7, 32), ref)",
3750
+ } {
3751
+ if !strings.Contains(text, want) {
3752
+ t.Fatalf("missing %q in generated output:\n%s", want, text)
3753
+ }
3754
+ }
3755
+ }
3756
+
3757
+ func TestCompilePackagesMarksFunctionLiteralAsyncForInterfaceMethodTypeSwitch(t *testing.T) {
3758
+ moduleDir := writePackageGraphFixture(t, map[string]string{
3759
+ "go.mod": "module example.test/funclittypeswitchawait\n\ngo 1.25.3\n",
3760
+ "main.go": strings.Join([]string{
3761
+ "package funclittypeswitchawait",
3762
+ "type GetPeer struct{}",
3763
+ "type Directive interface{ GetDirective() any }",
3764
+ "type Bridge struct{ keep func(Directive) (bool, error) }",
3765
+ "func NewBridge(keep func(Directive) (bool, error)) *Bridge { return &Bridge{keep: keep} }",
3766
+ "func Build() *Bridge {",
3767
+ " return NewBridge(func(di Directive) (bool, error) {",
3768
+ " switch di.GetDirective().(type) {",
3769
+ " case GetPeer:",
3770
+ " return false, nil",
3771
+ " }",
3772
+ " return true, nil",
3773
+ " })",
3774
+ "}",
3775
+ "",
3776
+ }, "\n"),
3777
+ })
3778
+ outputDir := filepath.Join(t.TempDir(), "output")
3779
+ comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
3780
+ if err != nil {
3781
+ t.Fatal(err.Error())
3782
+ }
3783
+
3784
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
3785
+ t.Fatal(err.Error())
3786
+ }
3787
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "funclittypeswitchawait", "main.gs.ts")
3788
+ content, err := os.ReadFile(outputFile)
3789
+ if err != nil {
3790
+ t.Fatal(err.Error())
3791
+ }
3792
+ text := string(content)
3793
+ for _, want := range []string{
3794
+ "$.functionValue(async (di: Directive | null): globalThis.Promise<[boolean, $.GoError]> => {",
3795
+ "const __goscriptTypeSwitchValue = await $.pointerValue<Exclude<Directive, null>>(di).GetDirective()",
3796
+ } {
3797
+ if !strings.Contains(text, want) {
3798
+ t.Fatalf("missing %q in generated output:\n%s", want, text)
3799
+ }
3800
+ }
3801
+ }
3802
+
3696
3803
  func TestCompilePackagesMarksRangeFuncAsyncWhenBodyAwaits(t *testing.T) {
3697
3804
  moduleDir := writePackageGraphFixture(t, map[string]string{
3698
3805
  "go.mod": "module example.test/rangefuncawaitbody\n\ngo 1.25.3\n",
@@ -3914,6 +4021,179 @@ func TestCompilePackagesPropagatesAsyncInterfaceMethodsFromTestImports(t *testin
3914
4021
  }
3915
4022
  }
3916
4023
 
4024
+ func TestCompilePackagesAwaitsAsyncInterfaceMethodSingleResultAssignment(t *testing.T) {
4025
+ moduleDir := writePackageGraphFixture(t, map[string]string{
4026
+ "go.mod": "module example.test/asyncifaceassign\n\ngo 1.25.3\n",
4027
+ "iface/controller.go": strings.Join([]string{
4028
+ "package iface",
4029
+ "import \"context\"",
4030
+ "type Controller interface {",
4031
+ " Execute(context.Context) error",
4032
+ "}",
4033
+ "",
4034
+ }, "\n"),
4035
+ "impl/controller.go": strings.Join([]string{
4036
+ "package impl",
4037
+ "import (",
4038
+ " \"context\"",
4039
+ " \"example.test/asyncifaceassign/iface\"",
4040
+ ")",
4041
+ "type Controller struct { ch chan struct{} }",
4042
+ "func NewController() iface.Controller {",
4043
+ " return &Controller{ch: make(chan struct{}, 1)}",
4044
+ "}",
4045
+ "func (c *Controller) Execute(ctx context.Context) error {",
4046
+ " select {",
4047
+ " case <-c.ch:",
4048
+ " return nil",
4049
+ " case <-ctx.Done():",
4050
+ " return ctx.Err()",
4051
+ " }",
4052
+ "}",
4053
+ "",
4054
+ }, "\n"),
4055
+ "use.go": strings.Join([]string{
4056
+ "package asyncifaceassign",
4057
+ "import (",
4058
+ " \"context\"",
4059
+ " \"example.test/asyncifaceassign/iface\"",
4060
+ ")",
4061
+ "func Run(ctx context.Context, c iface.Controller) error {",
4062
+ " err := c.Execute(ctx)",
4063
+ " return err",
4064
+ "}",
4065
+ "",
4066
+ }, "\n"),
4067
+ })
4068
+ outputDir := filepath.Join(t.TempDir(), "output")
4069
+ service := NewCompileService()
4070
+ _, err := service.Compile(context.Background(), &CompileRequest{
4071
+ Patterns: []string{".", "./iface", "./impl"},
4072
+ Dir: moduleDir,
4073
+ OutputPath: outputDir,
4074
+ DependencyMode: DependencyModeAll,
4075
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
4076
+ })
4077
+ if err != nil {
4078
+ t.Fatal(err.Error())
4079
+ }
4080
+
4081
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "asyncifaceassign", "use.gs.ts")
4082
+ content, err := os.ReadFile(outputFile)
4083
+ if err != nil {
4084
+ t.Fatal(err.Error())
4085
+ }
4086
+ text := string(content)
4087
+ if want := "let err = await $.pointerValue<Exclude<iface.Controller, null>>(c).Execute(ctx)"; !strings.Contains(text, want) {
4088
+ t.Fatalf("single-result async interface assignment was not awaited:\n%s", text)
4089
+ }
4090
+ }
4091
+
4092
+ func TestCompilePackagesAwaitsInterfaceMethodCallInsideAsyncCallerWithoutKnownImplementation(t *testing.T) {
4093
+ moduleDir := writePackageGraphFixture(t, map[string]string{
4094
+ "go.mod": "module example.test/asyncifaceunknownimpl\n\ngo 1.25.3\n",
4095
+ "iface/controller.go": strings.Join([]string{
4096
+ "package iface",
4097
+ "import \"context\"",
4098
+ "type Controller interface {",
4099
+ " Execute(context.Context) error",
4100
+ "}",
4101
+ "",
4102
+ }, "\n"),
4103
+ "use.go": strings.Join([]string{
4104
+ "package asyncifaceunknownimpl",
4105
+ "import (",
4106
+ " \"context\"",
4107
+ " \"example.test/asyncifaceunknownimpl/iface\"",
4108
+ ")",
4109
+ "func Run(ctx context.Context, c iface.Controller, ready <-chan struct{}) error {",
4110
+ " select {",
4111
+ " case <-ready:",
4112
+ " default:",
4113
+ " }",
4114
+ " err := c.Execute(ctx)",
4115
+ " return err",
4116
+ "}",
4117
+ "",
4118
+ }, "\n"),
4119
+ })
4120
+ outputDir := filepath.Join(t.TempDir(), "output")
4121
+ service := NewCompileService()
4122
+ _, err := service.Compile(context.Background(), &CompileRequest{
4123
+ Patterns: []string{".", "./iface"},
4124
+ Dir: moduleDir,
4125
+ OutputPath: outputDir,
4126
+ DependencyMode: DependencyModeAll,
4127
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
4128
+ })
4129
+ if err != nil {
4130
+ t.Fatal(err.Error())
4131
+ }
4132
+
4133
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "asyncifaceunknownimpl", "use.gs.ts")
4134
+ content, err := os.ReadFile(outputFile)
4135
+ if err != nil {
4136
+ t.Fatal(err.Error())
4137
+ }
4138
+ text := string(content)
4139
+ if want := "let err = await $.pointerValue<Exclude<iface.Controller, null>>(c).Execute(ctx)"; !strings.Contains(text, want) {
4140
+ t.Fatalf("async caller did not await interface method with unknown implementation:\n%s", text)
4141
+ }
4142
+ }
4143
+
4144
+ func TestCompilePackagesMarksNamedFunctionAsyncForInterfaceMethodCallWithoutKnownImplementation(t *testing.T) {
4145
+ moduleDir := writePackageGraphFixture(t, map[string]string{
4146
+ "go.mod": "module example.test/syncifaceunknownimpl\n\ngo 1.25.3\n",
4147
+ "iface/controller.go": strings.Join([]string{
4148
+ "package iface",
4149
+ "import \"context\"",
4150
+ "type Controller interface {",
4151
+ " Execute(context.Context) error",
4152
+ "}",
4153
+ "",
4154
+ }, "\n"),
4155
+ "use.go": strings.Join([]string{
4156
+ "package syncifaceunknownimpl",
4157
+ "import (",
4158
+ " \"context\"",
4159
+ " \"example.test/syncifaceunknownimpl/iface\"",
4160
+ ")",
4161
+ "func Run(ctx context.Context, c iface.Controller) error {",
4162
+ " err := c.Execute(ctx)",
4163
+ " return err",
4164
+ "}",
4165
+ "",
4166
+ }, "\n"),
4167
+ })
4168
+ outputDir := filepath.Join(t.TempDir(), "output")
4169
+ service := NewCompileService()
4170
+ _, err := service.Compile(context.Background(), &CompileRequest{
4171
+ Patterns: []string{".", "./iface"},
4172
+ Dir: moduleDir,
4173
+ OutputPath: outputDir,
4174
+ DependencyMode: DependencyModeAll,
4175
+ RuntimeEmissionMode: RuntimeEmissionModeEmit,
4176
+ })
4177
+ if err != nil {
4178
+ t.Fatal(err.Error())
4179
+ }
4180
+
4181
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "syncifaceunknownimpl", "use.gs.ts")
4182
+ content, err := os.ReadFile(outputFile)
4183
+ if err != nil {
4184
+ t.Fatal(err.Error())
4185
+ }
4186
+ text := string(content)
4187
+ for _, want := range []string{
4188
+ "export async function Run(ctx: context.Context | null, c: iface.Controller | null): globalThis.Promise<$.GoError>",
4189
+ "let err = await $.pointerValue<Exclude<iface.Controller, null>>(c).Execute(ctx)",
4190
+ } {
4191
+ if !strings.Contains(text, want) {
4192
+ t.Fatalf("missing %q in generated output:\n%s", want, text)
4193
+ }
4194
+ }
4195
+ }
4196
+
3917
4197
  func TestCompilePackagesMarksSelectReturningIfElseCasesUnreachable(t *testing.T) {
3918
4198
  moduleDir := writePackageGraphFixture(t, map[string]string{
3919
4199
  "go.mod": "module example.test/select-if-else\n\ngo 1.25.3\n",
@@ -4148,6 +4428,148 @@ func TestCompilePackagesParenthesizesAsyncFieldReceivers(t *testing.T) {
4148
4428
  }
4149
4429
  }
4150
4430
 
4431
+ func TestCompilePackagesAwaitsAsyncMethodValuesInAssignmentsAndReceivers(t *testing.T) {
4432
+ moduleDir := writePackageGraphFixture(t, map[string]string{
4433
+ "go.mod": "module example.test/asyncmethodvalues\n\ngo 1.25.3\n",
4434
+ "main.go": strings.Join([]string{
4435
+ "package asyncmethodvalues",
4436
+ "import \"reflect\"",
4437
+ "type Entry struct { value any }",
4438
+ "type Holder struct { entry *Entry }",
4439
+ "func (e *Entry) WithField(key string, value any) *Entry {",
4440
+ " return e.WithFields(map[string]any{key: value})",
4441
+ "}",
4442
+ "func (e *Entry) WithFields(fields map[string]any) *Entry {",
4443
+ " for _, value := range fields {",
4444
+ " if t := reflect.TypeOf(value); t != nil {",
4445
+ " switch {",
4446
+ " case t.Kind() == reflect.Func:",
4447
+ " e.value = value",
4448
+ " }",
4449
+ " }",
4450
+ " }",
4451
+ " return e",
4452
+ "}",
4453
+ "func (e *Entry) Warn(msg string) {}",
4454
+ "func Use(entry *Entry) {",
4455
+ " le := entry.WithField(\"first\", func(){})",
4456
+ " h := Holder{entry: entry.WithField(\"holder\", func(){})}",
4457
+ " _ = h",
4458
+ " le.WithField(\"second\", func(){}).Warn(\"done\")",
4459
+ "}",
4460
+ "",
4461
+ }, "\n"),
4462
+ })
4463
+ outputDir := filepath.Join(t.TempDir(), "output")
4464
+ comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
4465
+ if err != nil {
4466
+ t.Fatal(err.Error())
4467
+ }
4468
+
4469
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
4470
+ t.Fatal(err.Error())
4471
+ }
4472
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "asyncmethodvalues", "main.gs.ts")
4473
+ content, err := os.ReadFile(outputFile)
4474
+ if err != nil {
4475
+ t.Fatal(err.Error())
4476
+ }
4477
+ text := string(content)
4478
+ for _, want := range []string{
4479
+ "public async WithField(key: string, value: any): globalThis.Promise<Entry | $.VarRef<Entry> | null>",
4480
+ "let le: Entry | $.VarRef<Entry> | null = await Entry.prototype.WithField.call(entry, \"first\",",
4481
+ "const __goscriptLiteralField0 = await Entry.prototype.WithField.call(entry, \"holder\",",
4482
+ "Entry.prototype.Warn.call(await Entry.prototype.WithField.call(le, \"second\",",
4483
+ } {
4484
+ if !strings.Contains(text, want) {
4485
+ t.Fatalf("missing %q in generated output:\n%s", want, text)
4486
+ }
4487
+ }
4488
+ for _, bad := range []string{
4489
+ "let le: Entry | $.VarRef<Entry> | null = Entry.prototype.WithField.call",
4490
+ "const __goscriptLiteralField0 = Entry.prototype.WithField.call",
4491
+ "Entry.prototype.Warn.call(Entry.prototype.WithField.call",
4492
+ } {
4493
+ if strings.Contains(text, bad) {
4494
+ t.Fatalf("async method value was consumed without await at %q:\n%s", bad, text)
4495
+ }
4496
+ }
4497
+ }
4498
+
4499
+ func TestCompilePackagesKeepsErrorInterfaceErrorSynchronous(t *testing.T) {
4500
+ moduleDir := writePackageGraphFixture(t, map[string]string{
4501
+ "go.mod": "module example.test/syncerrorstring\n\ngo 1.25.3\n",
4502
+ "main.go": strings.Join([]string{
4503
+ "package syncerrorstring",
4504
+ "type wrappedError struct {",
4505
+ " cause error",
4506
+ " msg string",
4507
+ "}",
4508
+ "func (w *wrappedError) Error() string {",
4509
+ " return w.msg + \": \" + w.cause.Error()",
4510
+ "}",
4511
+ "type healthError struct {",
4512
+ " cause error",
4513
+ " health string",
4514
+ "}",
4515
+ "type HealthError interface {",
4516
+ " error",
4517
+ " GetHealth() string",
4518
+ "}",
4519
+ "func (h *healthError) Error() string {",
4520
+ " if h.cause != nil {",
4521
+ " return h.cause.Error()",
4522
+ " }",
4523
+ " return h.health",
4524
+ "}",
4525
+ "func (h *healthError) GetHealth() string { return h.health }",
4526
+ "type baseError string",
4527
+ "func (b baseError) Error() string { return string(b) }",
4528
+ "func NewWrapped() error {",
4529
+ " return &wrappedError{msg: \"load\", cause: &healthError{cause: baseError(\"missing\")}}",
4530
+ "}",
4531
+ "func ReadHealthError(h HealthError) string {",
4532
+ " return h.Error()",
4533
+ "}",
4534
+ "",
4535
+ }, "\n"),
4536
+ })
4537
+ outputDir := filepath.Join(t.TempDir(), "output")
4538
+ comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
4539
+ if err != nil {
4540
+ t.Fatal(err.Error())
4541
+ }
4542
+
4543
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
4544
+ t.Fatal(err.Error())
4545
+ }
4546
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "syncerrorstring", "main.gs.ts")
4547
+ content, err := os.ReadFile(outputFile)
4548
+ if err != nil {
4549
+ t.Fatal(err.Error())
4550
+ }
4551
+ text := string(content)
4552
+ for _, want := range []string{
4553
+ "public Error(): string {",
4554
+ "return ($.pointerValue<wrappedError>(w).msg + \": \") + $.pointerValue<Exclude<$.GoError, null>>($.pointerValue<wrappedError>(w).cause).Error()",
4555
+ "return $.pointerValue<Exclude<$.GoError, null>>($.pointerValue<healthError>(h).cause).Error()",
4556
+ } {
4557
+ if !strings.Contains(text, want) {
4558
+ t.Fatalf("missing %q in generated output:\n%s", want, text)
4559
+ }
4560
+ }
4561
+ for _, bad := range []string{
4562
+ "public async Error(): globalThis.Promise<string>",
4563
+ "await $.pointerValue<Exclude<$.GoError, null>>($.pointerValue<wrappedError>(w).cause).Error()",
4564
+ "await $.pointerValue<Exclude<$.GoError, null>>($.pointerValue<healthError>(h).cause).Error()",
4565
+ "await $.pointerValue<HealthError>(h).Error()",
4566
+ } {
4567
+ if strings.Contains(text, bad) {
4568
+ t.Fatalf("error stringification became async at %q:\n%s", bad, text)
4569
+ }
4570
+ }
4571
+ }
4572
+
4151
4573
  func TestCompilePackagesScopesIfInitDeclarations(t *testing.T) {
4152
4574
  moduleDir := writePackageGraphFixture(t, map[string]string{
4153
4575
  "go.mod": "module example.test/ifinit\n\ngo 1.25.3\n",
@@ -4341,6 +4763,7 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
4341
4763
  "type Box struct {",
4342
4764
  " Value int",
4343
4765
  "}",
4766
+ "type Header map[string][]string",
4344
4767
  "",
4345
4768
  }, "\n"),
4346
4769
  "main.go": strings.Join([]string{
@@ -4352,6 +4775,7 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
4352
4775
  "type Holder struct {",
4353
4776
  " Box lib.Box",
4354
4777
  " Boxes []lib.Box",
4778
+ " Header lib.Header",
4355
4779
  " Fn func(lib.Box) (lib.Box, error)",
4356
4780
  " Ptr atomic.Pointer[func()]",
4357
4781
  "}",
@@ -4382,8 +4806,10 @@ func TestCompilePackagesQualifiesImportedTypesInSignaturesAndZeroValues(t *testi
4382
4806
  for _, want := range []string{
4383
4807
  "Box: $.VarRef<lib.Box>",
4384
4808
  "Boxes: $.VarRef<$.Slice<lib.Box>>",
4809
+ "Header: $.VarRef<lib.Header>",
4385
4810
  "Fn: $.VarRef<((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null>",
4386
4811
  "Ptr: $.VarRef<atomic.Pointer<(() => void) | null>>",
4812
+ "Header: $.varRef(init?.Header ?? (null as unknown as lib.Header))",
4387
4813
  "$.markAsStructValue(new lib.Box())",
4388
4814
  "$.markAsStructValue(new atomic.Pointer<(() => void) | null>())",
4389
4815
  "export async function Use(fn: ((_p0: lib.Box) => [lib.Box, $.GoError] | globalThis.Promise<[lib.Box, $.GoError]>) | null, box: lib.Box): globalThis.Promise<[lib.Box, $.GoError]>",
@@ -4508,7 +4934,7 @@ func TestCompilePackagesNormalizesWideIntegerReturnTargets(t *testing.T) {
4508
4934
  t.Fatal(err.Error())
4509
4935
  }
4510
4936
  text := string(content)
4511
- if !strings.Contains(text, "return $.uint($.pointerValue<Exclude<hash.Hash64, null>>(h).Sum64(), 64)") {
4937
+ if !strings.Contains(text, "return $.uint(await $.pointerValue<Exclude<hash.Hash64, null>>(h).Sum64(), 64)") {
4512
4938
  t.Fatalf("missing uint64 return normalization:\n%s", text)
4513
4939
  }
4514
4940
  }
@@ -4592,6 +5018,41 @@ func TestCompilePackagesUnwrapsOverridePointerMethodReceiver(t *testing.T) {
4592
5018
  }
4593
5019
  }
4594
5020
 
5021
+ func TestCompilePackagesUsesRuntimeValueForAbsentSelectedReceiverType(t *testing.T) {
5022
+ moduleDir := writePackageGraphFixture(t, map[string]string{
5023
+ "go.mod": "module example.test/selected-receiver-import\n\ngo 1.25.3\n",
5024
+ "main.go": strings.Join([]string{
5025
+ "package main",
5026
+ "import \"net/http\"",
5027
+ "func URLString(req *http.Request) string {",
5028
+ " return req.URL.String()",
5029
+ "}",
5030
+ "",
5031
+ }, "\n"),
5032
+ })
5033
+ outputDir := filepath.Join(t.TempDir(), "output")
5034
+ comp, err := NewCompiler(&Config{Dir: moduleDir, OutputPath: outputDir}, nil, nil)
5035
+ if err != nil {
5036
+ t.Fatal(err.Error())
5037
+ }
5038
+
5039
+ if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
5040
+ t.Fatal(err.Error())
5041
+ }
5042
+ outputFile := filepath.Join(outputDir, "@goscript", "example.test", "selected-receiver-import", "main.gs.ts")
5043
+ content, err := os.ReadFile(outputFile)
5044
+ if err != nil {
5045
+ t.Fatal(err.Error())
5046
+ }
5047
+ text := string(content)
5048
+ if strings.Contains(text, "URL.prototype.String.call") {
5049
+ t.Fatalf("selected receiver method call used unqualified type:\n%s", text)
5050
+ }
5051
+ if !strings.Contains(text, "$.pointerValue<http.Request>(req).URL.String()") {
5052
+ t.Fatalf("selected receiver method call did not use runtime value method:\n%s", text)
5053
+ }
5054
+ }
5055
+
4595
5056
  func TestCompilePackagesUnwrapsImportedArrayPackageVarReads(t *testing.T) {
4596
5057
  moduleDir := writePackageGraphFixture(t, map[string]string{
4597
5058
  "go.mod": "module example.test/imported-array-var\n\ngo 1.25.3\n",
@@ -456,7 +456,11 @@ func renderStruct(b *strings.Builder, structType *loweredStruct, runtimeOwner *R
456
456
  b.WriteString("init?.")
457
457
  b.WriteString(field.name)
458
458
  b.WriteString(" ?? ")
459
+ b.WriteString("(")
459
460
  b.WriteString(field.zero)
461
+ b.WriteString(" as unknown as ")
462
+ b.WriteString(field.typ)
463
+ b.WriteString(")")
460
464
  }
461
465
  b.WriteString(")")
462
466
  if idx != len(structType.fields)-1 {