From 6dd4013a095cd5c663e93412a78de58ab6ddd5cb Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 27 Sep 2026 08:35:34 -0700 Subject: [PATCH 1/3] Don't reduce intersections of mappings of the same object type --- tsc/internal/checker/checker.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tsc/internal/checker/checker.go b/tsc/internal/checker/checker.go index 8aec6df21d7af..9524e5e5b36a9 100644 --- a/tsc/internal/checker/checker.go +++ b/tsc/internal/checker/checker.go @@ -22183,7 +22183,7 @@ func (c *Checker) getReducedType(t *Type) *Type { case t.flags&TypeFlagsIntersection != 0: if t.objectFlags&ObjectFlagsIsNeverIntersectionComputed == 0 { t.objectFlags |= ObjectFlagsIsNeverIntersectionComputed - if core.Some(c.getPropertiesOfUnionOrIntersectionType(t), c.isNeverReducedProperty) { + if !c.isMappingOfSameObjectType(t.Types()) && core.Some(c.getPropertiesOfUnionOrIntersectionType(t), c.isNeverReducedProperty) { t.objectFlags |= ObjectFlagsIsNeverIntersection } } @@ -22194,6 +22194,20 @@ func (c *Checker) getReducedType(t *Type) *Type { return t } +func (c *Checker) isMappingOfSameObjectType(types []*Type) bool { + if len(types) != 0 && types[0].objectFlags&ObjectFlagsMapped != 0 { + if firstType := c.getModifiersTypeFromMappedType(types[0]); firstType.flags&TypeFlagsObject != 0 { + for _, t := range types[1:] { + if t.objectFlags&ObjectFlagsMapped == 0 || c.getModifiersTypeFromMappedType(t) != firstType { + return false + } + } + return true + } + } + return false +} + func (c *Checker) getReducedUnionType(unionType *Type) *Type { reducedTypes := core.SameMap(unionType.Types(), c.getReducedType) if core.Same(reducedTypes, unionType.Types()) { From e0651276a60cab9ae1f9845fd1d8ddff73d0e447 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 27 Sep 2026 08:35:52 -0700 Subject: [PATCH 2/3] Accept new baselines --- .../baselines/reference/compiler/recursiveTypeInference.types | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTypeInference.types b/tsc/testdata/baselines/reference/compiler/recursiveTypeInference.types index 914b8260ed821..95a0369a05563 100644 --- a/tsc/testdata/baselines/reference/compiler/recursiveTypeInference.types +++ b/tsc/testdata/baselines/reference/compiler/recursiveTypeInference.types @@ -315,7 +315,7 @@ const Activity = z.object({ }, }); export type ActivityT = output; ->ActivityT : { name: string; subactivities: unknown; } +>ActivityT : { name: string; subactivities: any[] | null; } >Activity : $ZodObject<{ name: $ZodString; readonly subactivities: $ZodNullable<$ZodArray<$ZodObject>>; }> // (4) reference through a separately-declared const @@ -355,6 +355,6 @@ const NodeArray = z.array(Node1); >Node1 : $ZodObject<{ name: $ZodString; readonly children: $ZodOptional<$ZodArray<$ZodObject>>; }> export type Node1T = output; ->Node1T : { name: string; children?: unknown; } +>Node1T : { name: string; children?: any[] | undefined; } >Node1 : $ZodObject<{ name: $ZodString; readonly children: $ZodOptional<$ZodArray<$ZodObject>>; }> From daf10b8bb4ea5159c244fba5b5ebb39e17769831 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 27 Sep 2026 08:41:10 -0700 Subject: [PATCH 3/3] Add regression test --- .../compiler/recursiveTypeInference2.symbols | 313 ++++++++++++++++++ .../compiler/recursiveTypeInference2.types | 152 +++++++++ .../cases/compiler/recursiveTypeInference2.ts | 48 +++ 3 files changed, 513 insertions(+) create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveTypeInference2.symbols create mode 100644 tsc/testdata/baselines/reference/compiler/recursiveTypeInference2.types create mode 100644 tsc/testdata/tests/cases/compiler/recursiveTypeInference2.ts diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTypeInference2.symbols b/tsc/testdata/baselines/reference/compiler/recursiveTypeInference2.symbols new file mode 100644 index 0000000000000..0fd2e63a8a3a5 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/recursiveTypeInference2.symbols @@ -0,0 +1,313 @@ +//// [tests/cases/compiler/recursiveTypeInference2.ts] //// + +=== recursiveTypeInference2.ts === +// https://github.com/microsoft/TypeScript/issues/64415 + +type output = T extends { _zod: { output: any } } ? T["_zod"]["output"] : unknown; +>output : Symbol(output, Decl(recursiveTypeInference2.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 2, 12)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 2, 12)) +>_zod : Symbol(_zod, Decl(recursiveTypeInference2.ts, 2, 28)) +>output : Symbol(output, Decl(recursiveTypeInference2.ts, 2, 36)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 2, 12)) + +type input = T extends { _zod: { input: any } } ? T["_zod"]["input"] : unknown; +>input : Symbol(input, Decl(recursiveTypeInference2.ts, 2, 85)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 3, 11)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 3, 11)) +>_zod : Symbol(_zod, Decl(recursiveTypeInference2.ts, 3, 27)) +>input : Symbol(input, Decl(recursiveTypeInference2.ts, 3, 35)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 3, 11)) + +type NoUndefined = T extends undefined ? never : T; +>NoUndefined : Symbol(NoUndefined, Decl(recursiveTypeInference2.ts, 3, 82)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 4, 17)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 4, 17)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 4, 17)) + +type Writeable = { -readonly [P in keyof T]: T[P] }; +>Writeable : Symbol(Writeable, Decl(recursiveTypeInference2.ts, 4, 54)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 5, 15)) +>P : Symbol(P, Decl(recursiveTypeInference2.ts, 5, 33)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 5, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 5, 15)) +>P : Symbol(P, Decl(recursiveTypeInference2.ts, 5, 33)) + +type Prettify = { [K in keyof T]: T[K] } & {}; +>Prettify : Symbol(Prettify, Decl(recursiveTypeInference2.ts, 5, 55)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 6, 14)) +>K : Symbol(K, Decl(recursiveTypeInference2.ts, 6, 22)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 6, 14)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 6, 14)) +>K : Symbol(K, Decl(recursiveTypeInference2.ts, 6, 22)) + +interface $ZodTypeInternals { def: unknown; output: O; input: I; optin?: "optional" | undefined; optout?: "optional" | undefined } +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>O : Symbol(O, Decl(recursiveTypeInference2.ts, 7, 28)) +>I : Symbol(I, Decl(recursiveTypeInference2.ts, 7, 44)) +>def : Symbol($ZodTypeInternals.def, Decl(recursiveTypeInference2.ts, 7, 63)) +>output : Symbol($ZodTypeInternals.output, Decl(recursiveTypeInference2.ts, 7, 77)) +>O : Symbol(O, Decl(recursiveTypeInference2.ts, 7, 28)) +>input : Symbol($ZodTypeInternals.input, Decl(recursiveTypeInference2.ts, 7, 88)) +>I : Symbol(I, Decl(recursiveTypeInference2.ts, 7, 44)) +>optin : Symbol($ZodTypeInternals.optin, Decl(recursiveTypeInference2.ts, 7, 98)) +>optout : Symbol($ZodTypeInternals.optout, Decl(recursiveTypeInference2.ts, 7, 130)) + +interface StandardProps { readonly types?: { readonly input: I; readonly output: O } | undefined } +>StandardProps : Symbol(StandardProps, Decl(recursiveTypeInference2.ts, 7, 164)) +>I : Symbol(I, Decl(recursiveTypeInference2.ts, 8, 24)) +>O : Symbol(O, Decl(recursiveTypeInference2.ts, 8, 26)) +>types : Symbol(StandardProps.types, Decl(recursiveTypeInference2.ts, 8, 31)) +>input : Symbol(input, Decl(recursiveTypeInference2.ts, 8, 50)) +>I : Symbol(I, Decl(recursiveTypeInference2.ts, 8, 24)) +>output : Symbol(output, Decl(recursiveTypeInference2.ts, 8, 69)) +>O : Symbol(O, Decl(recursiveTypeInference2.ts, 8, 26)) + +interface $ZodType = $ZodTypeInternals> { +>$ZodType : Symbol($ZodType, Decl(recursiveTypeInference2.ts, 8, 104)) +>O : Symbol(O, Decl(recursiveTypeInference2.ts, 9, 19)) +>I : Symbol(I, Decl(recursiveTypeInference2.ts, 9, 31)) +>Internals : Symbol(Internals, Decl(recursiveTypeInference2.ts, 9, 44)) +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>O : Symbol(O, Decl(recursiveTypeInference2.ts, 9, 19)) +>I : Symbol(I, Decl(recursiveTypeInference2.ts, 9, 31)) +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>O : Symbol(O, Decl(recursiveTypeInference2.ts, 9, 19)) +>I : Symbol(I, Decl(recursiveTypeInference2.ts, 9, 31)) + + _zod: Internals; +>_zod : Symbol($ZodType._zod, Decl(recursiveTypeInference2.ts, 9, 115)) +>Internals : Symbol(Internals, Decl(recursiveTypeInference2.ts, 9, 44)) + + "~standard": StandardProps, output>; +>"~standard" : Symbol($ZodType["~standard"], Decl(recursiveTypeInference2.ts, 10, 18)) +>StandardProps : Symbol(StandardProps, Decl(recursiveTypeInference2.ts, 7, 164)) +>input : Symbol(input, Decl(recursiveTypeInference2.ts, 2, 85)) +>output : Symbol(output, Decl(recursiveTypeInference2.ts, 0, 0)) +} +interface ZodType extends $ZodType { +>ZodType : Symbol(ZodType, Decl(recursiveTypeInference2.ts, 12, 1)) +>Internals : Symbol(Internals, Decl(recursiveTypeInference2.ts, 13, 18)) +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>$ZodType : Symbol($ZodType, Decl(recursiveTypeInference2.ts, 8, 104)) +>Internals : Symbol(Internals, Decl(recursiveTypeInference2.ts, 13, 18)) + + default(def: NoUndefined>): ZodDefault; +>default : Symbol(ZodType.default, Decl(recursiveTypeInference2.ts, 13, 118), Decl(recursiveTypeInference2.ts, 14, 60)) +>def : Symbol(def, Decl(recursiveTypeInference2.ts, 14, 10)) +>NoUndefined : Symbol(NoUndefined, Decl(recursiveTypeInference2.ts, 3, 82)) +>output : Symbol(output, Decl(recursiveTypeInference2.ts, 0, 0)) +>ZodDefault : Symbol(ZodDefault, Decl(recursiveTypeInference2.ts, 37, 195)) + + default(def: () => NoUndefined>): ZodDefault; +>default : Symbol(ZodType.default, Decl(recursiveTypeInference2.ts, 13, 118), Decl(recursiveTypeInference2.ts, 14, 60)) +>def : Symbol(def, Decl(recursiveTypeInference2.ts, 15, 10)) +>NoUndefined : Symbol(NoUndefined, Decl(recursiveTypeInference2.ts, 3, 82)) +>output : Symbol(output, Decl(recursiveTypeInference2.ts, 0, 0)) +>ZodDefault : Symbol(ZodDefault, Decl(recursiveTypeInference2.ts, 37, 195)) +} +type Shape = Readonly<{ [k: string]: $ZodType }>; +>Shape : Symbol(Shape, Decl(recursiveTypeInference2.ts, 16, 1)) +>Readonly : Symbol(Readonly, Decl(lib.es5.d.ts, --, --)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 17, 25)) +>$ZodType : Symbol($ZodType, Decl(recursiveTypeInference2.ts, 8, 104)) + +type OptionalOut = { _zod: { optout: "optional" } }; +>OptionalOut : Symbol(OptionalOut, Decl(recursiveTypeInference2.ts, 17, 49)) +>_zod : Symbol(_zod, Decl(recursiveTypeInference2.ts, 18, 20)) +>optout : Symbol(optout, Decl(recursiveTypeInference2.ts, 18, 28)) + +type OptionalIn = { _zod: { optin: "optional" } }; +>OptionalIn : Symbol(OptionalIn, Decl(recursiveTypeInference2.ts, 18, 52)) +>_zod : Symbol(_zod, Decl(recursiveTypeInference2.ts, 19, 19)) +>optin : Symbol(optin, Decl(recursiveTypeInference2.ts, 19, 27)) + +type $InferObjectOutput = Prettify< +>$InferObjectOutput : Symbol($InferObjectOutput, Decl(recursiveTypeInference2.ts, 19, 50)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 20, 24)) +>Shape : Symbol(Shape, Decl(recursiveTypeInference2.ts, 16, 1)) +>Prettify : Symbol(Prettify, Decl(recursiveTypeInference2.ts, 5, 55)) + + { -readonly [k in keyof T as T[k] extends OptionalOut ? never : k]: T[k]["_zod"]["output"] } & +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 21, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 20, 24)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 20, 24)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 21, 15)) +>OptionalOut : Symbol(OptionalOut, Decl(recursiveTypeInference2.ts, 17, 49)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 21, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 20, 24)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 21, 15)) + + { -readonly [k in keyof T as T[k] extends OptionalOut ? k : never]?: T[k]["_zod"]["output"] } +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 22, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 20, 24)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 20, 24)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 22, 15)) +>OptionalOut : Symbol(OptionalOut, Decl(recursiveTypeInference2.ts, 17, 49)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 22, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 20, 24)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 22, 15)) + +>; +type $InferObjectInput = Prettify< +>$InferObjectInput : Symbol($InferObjectInput, Decl(recursiveTypeInference2.ts, 23, 2)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 24, 23)) +>Shape : Symbol(Shape, Decl(recursiveTypeInference2.ts, 16, 1)) +>Prettify : Symbol(Prettify, Decl(recursiveTypeInference2.ts, 5, 55)) + + { -readonly [k in keyof T as T[k] extends OptionalIn ? never : k]: T[k]["_zod"]["input"] } & +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 25, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 24, 23)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 24, 23)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 25, 15)) +>OptionalIn : Symbol(OptionalIn, Decl(recursiveTypeInference2.ts, 18, 52)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 25, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 24, 23)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 25, 15)) + + { -readonly [k in keyof T as T[k] extends OptionalIn ? k : never]?: T[k]["_zod"]["input"] } +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 26, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 24, 23)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 24, 23)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 26, 15)) +>OptionalIn : Symbol(OptionalIn, Decl(recursiveTypeInference2.ts, 18, 52)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 26, 15)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 24, 23)) +>k : Symbol(k, Decl(recursiveTypeInference2.ts, 26, 15)) + +>; +interface $ZodStringInternals extends $ZodTypeInternals { def: { type: "string" }; output: string; input: string } +>$ZodStringInternals : Symbol($ZodStringInternals, Decl(recursiveTypeInference2.ts, 27, 2)) +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>def : Symbol($ZodStringInternals.def, Decl(recursiveTypeInference2.ts, 28, 57)) +>type : Symbol(type, Decl(recursiveTypeInference2.ts, 28, 64)) +>output : Symbol($ZodStringInternals.output, Decl(recursiveTypeInference2.ts, 28, 82)) +>input : Symbol($ZodStringInternals.input, Decl(recursiveTypeInference2.ts, 28, 98)) + +interface ZodString extends ZodType<$ZodStringInternals> {} +>ZodString : Symbol(ZodString, Decl(recursiveTypeInference2.ts, 28, 114)) +>ZodType : Symbol(ZodType, Decl(recursiveTypeInference2.ts, 12, 1)) +>$ZodStringInternals : Symbol($ZodStringInternals, Decl(recursiveTypeInference2.ts, 27, 2)) + +declare function string(): ZodString; +>string : Symbol(string, Decl(recursiveTypeInference2.ts, 29, 59)) +>ZodString : Symbol(ZodString, Decl(recursiveTypeInference2.ts, 28, 114)) + +interface $ZodObjectInternals extends $ZodTypeInternals { def: { type: "object"; shape: S }; output: $InferObjectOutput; input: $InferObjectInput } +>$ZodObjectInternals : Symbol($ZodObjectInternals, Decl(recursiveTypeInference2.ts, 30, 37)) +>S : Symbol(S, Decl(recursiveTypeInference2.ts, 31, 30)) +>Shape : Symbol(Shape, Decl(recursiveTypeInference2.ts, 16, 1)) +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>def : Symbol($ZodObjectInternals.def, Decl(recursiveTypeInference2.ts, 31, 74)) +>type : Symbol(type, Decl(recursiveTypeInference2.ts, 31, 81)) +>shape : Symbol(shape, Decl(recursiveTypeInference2.ts, 31, 97)) +>S : Symbol(S, Decl(recursiveTypeInference2.ts, 31, 30)) +>output : Symbol($ZodObjectInternals.output, Decl(recursiveTypeInference2.ts, 31, 109)) +>$InferObjectOutput : Symbol($InferObjectOutput, Decl(recursiveTypeInference2.ts, 19, 50)) +>S : Symbol(S, Decl(recursiveTypeInference2.ts, 31, 30)) +>input : Symbol($ZodObjectInternals.input, Decl(recursiveTypeInference2.ts, 31, 140)) +>$InferObjectInput : Symbol($InferObjectInput, Decl(recursiveTypeInference2.ts, 23, 2)) +>S : Symbol(S, Decl(recursiveTypeInference2.ts, 31, 30)) + +interface ZodObject extends ZodType<$ZodObjectInternals> { shape: S } +>ZodObject : Symbol(ZodObject, Decl(recursiveTypeInference2.ts, 31, 170)) +>S : Symbol(S, Decl(recursiveTypeInference2.ts, 32, 20)) +>Shape : Symbol(Shape, Decl(recursiveTypeInference2.ts, 16, 1)) +>ZodType : Symbol(ZodType, Decl(recursiveTypeInference2.ts, 12, 1)) +>$ZodObjectInternals : Symbol($ZodObjectInternals, Decl(recursiveTypeInference2.ts, 30, 37)) +>S : Symbol(S, Decl(recursiveTypeInference2.ts, 32, 20)) +>shape : Symbol(ZodObject.shape, Decl(recursiveTypeInference2.ts, 32, 78)) +>S : Symbol(S, Decl(recursiveTypeInference2.ts, 32, 20)) + +declare function object(shape: T): ZodObject>; +>object : Symbol(object, Decl(recursiveTypeInference2.ts, 32, 89)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 33, 24)) +>Shape : Symbol(Shape, Decl(recursiveTypeInference2.ts, 16, 1)) +>shape : Symbol(shape, Decl(recursiveTypeInference2.ts, 33, 41)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 33, 24)) +>ZodObject : Symbol(ZodObject, Decl(recursiveTypeInference2.ts, 31, 170)) +>Writeable : Symbol(Writeable, Decl(recursiveTypeInference2.ts, 4, 54)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 33, 24)) + +interface $ZodArrayInternals extends $ZodTypeInternals { def: { type: "array"; element: T }; output: output[]; input: input[] } +>$ZodArrayInternals : Symbol($ZodArrayInternals, Decl(recursiveTypeInference2.ts, 33, 76)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 34, 29)) +>$ZodType : Symbol($ZodType, Decl(recursiveTypeInference2.ts, 8, 104)) +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>def : Symbol($ZodArrayInternals.def, Decl(recursiveTypeInference2.ts, 34, 76)) +>type : Symbol(type, Decl(recursiveTypeInference2.ts, 34, 83)) +>element : Symbol(element, Decl(recursiveTypeInference2.ts, 34, 98)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 34, 29)) +>output : Symbol($ZodArrayInternals.output, Decl(recursiveTypeInference2.ts, 34, 112)) +>output : Symbol(output, Decl(recursiveTypeInference2.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 34, 29)) +>input : Symbol($ZodArrayInternals.input, Decl(recursiveTypeInference2.ts, 34, 133)) +>input : Symbol(input, Decl(recursiveTypeInference2.ts, 2, 85)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 34, 29)) + +interface ZodArray extends ZodType<$ZodArrayInternals> { element: T } +>ZodArray : Symbol(ZodArray, Decl(recursiveTypeInference2.ts, 34, 153)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 35, 19)) +>$ZodType : Symbol($ZodType, Decl(recursiveTypeInference2.ts, 8, 104)) +>ZodType : Symbol(ZodType, Decl(recursiveTypeInference2.ts, 12, 1)) +>$ZodArrayInternals : Symbol($ZodArrayInternals, Decl(recursiveTypeInference2.ts, 33, 76)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 35, 19)) +>element : Symbol(ZodArray.element, Decl(recursiveTypeInference2.ts, 35, 79)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 35, 19)) + +declare function array(element: T): ZodArray; +>array : Symbol(array, Decl(recursiveTypeInference2.ts, 35, 92)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 36, 23)) +>$ZodType : Symbol($ZodType, Decl(recursiveTypeInference2.ts, 8, 104)) +>element : Symbol(element, Decl(recursiveTypeInference2.ts, 36, 43)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 36, 23)) +>ZodArray : Symbol(ZodArray, Decl(recursiveTypeInference2.ts, 34, 153)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 36, 23)) + +interface $ZodDefaultInternals extends $ZodTypeInternals { def: { type: "default"; inner: T }; output: NoUndefined>; input: input | undefined; optin: "optional" } +>$ZodDefaultInternals : Symbol($ZodDefaultInternals, Decl(recursiveTypeInference2.ts, 36, 68)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 37, 31)) +>$ZodType : Symbol($ZodType, Decl(recursiveTypeInference2.ts, 8, 104)) +>$ZodTypeInternals : Symbol($ZodTypeInternals, Decl(recursiveTypeInference2.ts, 6, 49)) +>def : Symbol($ZodDefaultInternals.def, Decl(recursiveTypeInference2.ts, 37, 78)) +>type : Symbol(type, Decl(recursiveTypeInference2.ts, 37, 85)) +>inner : Symbol(inner, Decl(recursiveTypeInference2.ts, 37, 102)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 37, 31)) +>output : Symbol($ZodDefaultInternals.output, Decl(recursiveTypeInference2.ts, 37, 114)) +>NoUndefined : Symbol(NoUndefined, Decl(recursiveTypeInference2.ts, 3, 82)) +>output : Symbol(output, Decl(recursiveTypeInference2.ts, 0, 0)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 37, 31)) +>input : Symbol($ZodDefaultInternals.input, Decl(recursiveTypeInference2.ts, 37, 146)) +>input : Symbol(input, Decl(recursiveTypeInference2.ts, 2, 85)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 37, 31)) +>optin : Symbol($ZodDefaultInternals.optin, Decl(recursiveTypeInference2.ts, 37, 175)) + +interface ZodDefault extends ZodType<$ZodDefaultInternals> {} +>ZodDefault : Symbol(ZodDefault, Decl(recursiveTypeInference2.ts, 37, 195)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 38, 21)) +>$ZodType : Symbol($ZodType, Decl(recursiveTypeInference2.ts, 8, 104)) +>ZodType : Symbol(ZodType, Decl(recursiveTypeInference2.ts, 12, 1)) +>$ZodDefaultInternals : Symbol($ZodDefaultInternals, Decl(recursiveTypeInference2.ts, 36, 68)) +>T : Symbol(T, Decl(recursiveTypeInference2.ts, 38, 21)) + +const Tree = object({ +>Tree : Symbol(Tree, Decl(recursiveTypeInference2.ts, 40, 5)) +>object : Symbol(object, Decl(recursiveTypeInference2.ts, 32, 89)) + + name: string(), +>name : Symbol(name, Decl(recursiveTypeInference2.ts, 40, 21)) +>string : Symbol(string, Decl(recursiveTypeInference2.ts, 29, 59)) + + get children() { +>children : Symbol(children, Decl(recursiveTypeInference2.ts, 41, 17)) + + return array(Tree).default([]) +>array(Tree).default : Symbol(ZodType.default, Decl(recursiveTypeInference2.ts, 13, 118), Decl(recursiveTypeInference2.ts, 14, 60)) +>array : Symbol(array, Decl(recursiveTypeInference2.ts, 35, 92)) +>Tree : Symbol(Tree, Decl(recursiveTypeInference2.ts, 40, 5)) +>default : Symbol(ZodType.default, Decl(recursiveTypeInference2.ts, 13, 118), Decl(recursiveTypeInference2.ts, 14, 60)) + + }, +}); + diff --git a/tsc/testdata/baselines/reference/compiler/recursiveTypeInference2.types b/tsc/testdata/baselines/reference/compiler/recursiveTypeInference2.types new file mode 100644 index 0000000000000..5cba09f8890e8 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/recursiveTypeInference2.types @@ -0,0 +1,152 @@ +//// [tests/cases/compiler/recursiveTypeInference2.ts] //// + +=== recursiveTypeInference2.ts === +// https://github.com/microsoft/TypeScript/issues/64415 + +type output = T extends { _zod: { output: any } } ? T["_zod"]["output"] : unknown; +>output : output +>_zod : { output: any; } +>output : any + +type input = T extends { _zod: { input: any } } ? T["_zod"]["input"] : unknown; +>input : input +>_zod : { input: any; } +>input : any + +type NoUndefined = T extends undefined ? never : T; +>NoUndefined : NoUndefined + +type Writeable = { -readonly [P in keyof T]: T[P] }; +>Writeable : Writeable + +type Prettify = { [K in keyof T]: T[K] } & {}; +>Prettify : { [K in keyof T]: T[K]; } + +interface $ZodTypeInternals { def: unknown; output: O; input: I; optin?: "optional" | undefined; optout?: "optional" | undefined } +>def : unknown +>output : O +>input : I +>optin : "optional" | undefined +>optout : "optional" | undefined + +interface StandardProps { readonly types?: { readonly input: I; readonly output: O } | undefined } +>types : { readonly input: I; readonly output: O; } | undefined +>input : I +>output : O + +interface $ZodType = $ZodTypeInternals> { + _zod: Internals; +>_zod : Internals + + "~standard": StandardProps, output>; +>"~standard" : StandardProps, output> +} +interface ZodType extends $ZodType { + default(def: NoUndefined>): ZodDefault; +>default : { (def: NoUndefined>): ZodDefault; (def: () => NoUndefined>): ZodDefault; } +>def : NoUndefined> + + default(def: () => NoUndefined>): ZodDefault; +>default : { (def: NoUndefined>): ZodDefault; (def: () => NoUndefined>): ZodDefault; } +>def : () => NoUndefined> +} +type Shape = Readonly<{ [k: string]: $ZodType }>; +>Shape : Readonly<{ [k: string]: $ZodType>; }> +>k : string + +type OptionalOut = { _zod: { optout: "optional" } }; +>OptionalOut : OptionalOut +>_zod : { optout: "optional"; } +>optout : "optional" + +type OptionalIn = { _zod: { optin: "optional" } }; +>OptionalIn : OptionalIn +>_zod : { optin: "optional"; } +>optin : "optional" + +type $InferObjectOutput = Prettify< +>$InferObjectOutput : { -readonly [k in keyof T as T[k] extends OptionalOut ? never : k]: T[k]["_zod"]["output"]; } & { -readonly [k in keyof T as T[k] extends OptionalOut ? k : never]?: T[k]["_zod"]["output"] | undefined; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never + + { -readonly [k in keyof T as T[k] extends OptionalOut ? never : k]: T[k]["_zod"]["output"] } & + { -readonly [k in keyof T as T[k] extends OptionalOut ? k : never]?: T[k]["_zod"]["output"] } +>; +type $InferObjectInput = Prettify< +>$InferObjectInput : { -readonly [k in keyof T as T[k] extends OptionalIn ? never : k]: T[k]["_zod"]["input"]; } & { -readonly [k in keyof T as T[k] extends OptionalIn ? k : never]?: T[k]["_zod"]["input"] | undefined; } extends infer T_1 ? { [K in keyof T_1]: T_1[K]; } : never + + { -readonly [k in keyof T as T[k] extends OptionalIn ? never : k]: T[k]["_zod"]["input"] } & + { -readonly [k in keyof T as T[k] extends OptionalIn ? k : never]?: T[k]["_zod"]["input"] } +>; +interface $ZodStringInternals extends $ZodTypeInternals { def: { type: "string" }; output: string; input: string } +>def : { type: "string"; } +>type : "string" +>output : string +>input : string + +interface ZodString extends ZodType<$ZodStringInternals> {} +declare function string(): ZodString; +>string : () => ZodString + +interface $ZodObjectInternals extends $ZodTypeInternals { def: { type: "object"; shape: S }; output: $InferObjectOutput; input: $InferObjectInput } +>def : { type: "object"; shape: S; } +>type : "object" +>shape : S +>output : { -readonly [k in keyof S as S[k] extends OptionalOut ? never : k]: S[k]["_zod"]["output"]; } & { -readonly [k in keyof S as S[k] extends OptionalOut ? k : never]?: S[k]["_zod"]["output"] | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never +>input : { -readonly [k in keyof S as S[k] extends OptionalIn ? never : k]: S[k]["_zod"]["input"]; } & { -readonly [k in keyof S as S[k] extends OptionalIn ? k : never]?: S[k]["_zod"]["input"] | undefined; } extends infer T ? { [K in keyof T]: T[K]; } : never + +interface ZodObject extends ZodType<$ZodObjectInternals> { shape: S } +>shape : S + +declare function object(shape: T): ZodObject>; +>object : (shape: T) => ZodObject> +>shape : T + +interface $ZodArrayInternals extends $ZodTypeInternals { def: { type: "array"; element: T }; output: output[]; input: input[] } +>def : { type: "array"; element: T; } +>type : "array" +>element : T +>output : output[] +>input : input[] + +interface ZodArray extends ZodType<$ZodArrayInternals> { element: T } +>element : T + +declare function array(element: T): ZodArray; +>array : (element: T) => ZodArray +>element : T + +interface $ZodDefaultInternals extends $ZodTypeInternals { def: { type: "default"; inner: T }; output: NoUndefined>; input: input | undefined; optin: "optional" } +>def : { type: "default"; inner: T; } +>type : "default" +>inner : T +>output : NoUndefined> +>input : input | undefined +>optin : "optional" + +interface ZodDefault extends ZodType<$ZodDefaultInternals> {} + +const Tree = object({ +>Tree : ZodObject>>>; }>> +>object({ name: string(), get children() { return array(Tree).default([]) },}) : ZodObject>>>; }>> +>object : (shape: T) => ZodObject> +>{ name: string(), get children() { return array(Tree).default([]) },} : { name: ZodString; readonly children: ZodDefault>>>; }>>>>; } + + name: string(), +>name : ZodString +>string() : ZodString +>string : () => ZodString + + get children() { +>children : ZodDefault>>>; }>>>> + + return array(Tree).default([]) +>array(Tree).default([]) : ZodDefault>>>; }>>>> +>array(Tree).default : { (def: { name: string; children: any[]; }[]): ZodDefault>>>; }>>>>; (def: () => { name: string; children: any[]; }[]): ZodDefault>>>; }>>>>; } +>array(Tree) : ZodArray>>>; }>>> +>array : (element: T) => ZodArray +>Tree : ZodObject>>>; }>> +>default : { (def: { name: string; children: any[]; }[]): ZodDefault>>>; }>>>>; (def: () => { name: string; children: any[]; }[]): ZodDefault>>>; }>>>>; } +>[] : never[] + + }, +}); + diff --git a/tsc/testdata/tests/cases/compiler/recursiveTypeInference2.ts b/tsc/testdata/tests/cases/compiler/recursiveTypeInference2.ts new file mode 100644 index 0000000000000..138c823a772e0 --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/recursiveTypeInference2.ts @@ -0,0 +1,48 @@ +// @noEmit: true + +// https://github.com/microsoft/TypeScript/issues/64415 + +type output = T extends { _zod: { output: any } } ? T["_zod"]["output"] : unknown; +type input = T extends { _zod: { input: any } } ? T["_zod"]["input"] : unknown; +type NoUndefined = T extends undefined ? never : T; +type Writeable = { -readonly [P in keyof T]: T[P] }; +type Prettify = { [K in keyof T]: T[K] } & {}; +interface $ZodTypeInternals { def: unknown; output: O; input: I; optin?: "optional" | undefined; optout?: "optional" | undefined } +interface StandardProps { readonly types?: { readonly input: I; readonly output: O } | undefined } +interface $ZodType = $ZodTypeInternals> { + _zod: Internals; + "~standard": StandardProps, output>; +} +interface ZodType extends $ZodType { + default(def: NoUndefined>): ZodDefault; + default(def: () => NoUndefined>): ZodDefault; +} +type Shape = Readonly<{ [k: string]: $ZodType }>; +type OptionalOut = { _zod: { optout: "optional" } }; +type OptionalIn = { _zod: { optin: "optional" } }; +type $InferObjectOutput = Prettify< + { -readonly [k in keyof T as T[k] extends OptionalOut ? never : k]: T[k]["_zod"]["output"] } & + { -readonly [k in keyof T as T[k] extends OptionalOut ? k : never]?: T[k]["_zod"]["output"] } +>; +type $InferObjectInput = Prettify< + { -readonly [k in keyof T as T[k] extends OptionalIn ? never : k]: T[k]["_zod"]["input"] } & + { -readonly [k in keyof T as T[k] extends OptionalIn ? k : never]?: T[k]["_zod"]["input"] } +>; +interface $ZodStringInternals extends $ZodTypeInternals { def: { type: "string" }; output: string; input: string } +interface ZodString extends ZodType<$ZodStringInternals> {} +declare function string(): ZodString; +interface $ZodObjectInternals extends $ZodTypeInternals { def: { type: "object"; shape: S }; output: $InferObjectOutput; input: $InferObjectInput } +interface ZodObject extends ZodType<$ZodObjectInternals> { shape: S } +declare function object(shape: T): ZodObject>; +interface $ZodArrayInternals extends $ZodTypeInternals { def: { type: "array"; element: T }; output: output[]; input: input[] } +interface ZodArray extends ZodType<$ZodArrayInternals> { element: T } +declare function array(element: T): ZodArray; +interface $ZodDefaultInternals extends $ZodTypeInternals { def: { type: "default"; inner: T }; output: NoUndefined>; input: input | undefined; optin: "optional" } +interface ZodDefault extends ZodType<$ZodDefaultInternals> {} + +const Tree = object({ + name: string(), + get children() { + return array(Tree).default([]) + }, +});