Environment
@typescript/native-preview (tsgo)
- Last good:
7.0.0-dev.20260421.2
- Broken:
7.0.0-dev.20260618.1 … 7.0.0-dev.20260622.1 (latest) — all fail
- Stable
typescript@5.9.3: OK (accepts the code)
So: same source, only the native-preview version changed → a tsgo regression somewhere between 20260421.2 and 20260618.1.
What breaks
A common recursive "serialize" utility type — maps Date | bigint → string recursively through objects and arrays, leaving everything else unchanged (so for a type X containing no Date/bigint, Transform<X> is structurally identical to X):
type Transform<Base, From, To> = {
[K in keyof Base]: Exclude<Base[K], undefined | null> extends never ? Base[K]
: Exclude<Base[K], undefined | null> extends object ? (Exclude<Base[K], undefined|null> extends From ? To | Extract<Base[K], null|undefined> : Transform<Base[K], From, To>)
: Base[K];
};
type TransformJson<T> = Transform<T, Date | bigint, string>;
For a deeply-nested compound type — recursion + arrays + an 8-member discriminated union with a shared base ({base} & ({type:1;…} | {type:2;…} | …)) nested several levels behind arrays — tsgo fails to prove TransformJson<X> assignable to X even when X has no Date/bigint (i.e. when the transform is provably the identity):
error TS2322: Type 'Transform<…, bigint | Date, string>' is not assignable to type '…'.
Type 'Transform<{base} & (…union…), bigint | Date, string>' is not assignable to '{base} & (…union…)'.
tsc proves this assignable; tsgo (new builds) does not.
Diagnosis / things tried (in case it helps narrow the regressed area)
- Adding an up-front "does this subtree contain
From?" guard so the transform returns Base verbatim for no-From subtrees → flips the failure into TS2589 "Type instantiation is excessively deep and possibly infinite" across the project, i.e. the extra recursive pass exhausts a depth/instantiation budget.
- Bounding the transform's recursion depth (no extra pass) → tsgo then fully expands the type (no TS2589) but still rejects the expanded
{base} & union intersection-with-union assignment.
- So it looks like two compounding limits: (a) a recursion/instantiation budget that's tighter or counted differently than in tsc, and (b) assignability of a mapped-type result back to an intersection-with-union, at depth.
Reproduction note (the awkward part)
I could not reduce this to a small standalone repro: the minimal/standalone versions of the exact pattern (even with the same 8-member intersection-with-union behind arrays) compile clean under both tsgo and tsc. It only reproduces inside a large real project (many hundreds of interacting Transform<…> instantiations across the program), which points at a scale-dependent / cumulative instantiation budget rather than a single-type defect.
Happy to help bisect against the dev-build range, or to share a private reproduction with the team if that's an option.
Environment
@typescript/native-preview(tsgo)7.0.0-dev.20260421.27.0.0-dev.20260618.1…7.0.0-dev.20260622.1(latest) — all failtypescript@5.9.3: OK (accepts the code)So: same source, only the native-preview version changed → a tsgo regression somewhere between
20260421.2and20260618.1.What breaks
A common recursive "serialize" utility type — maps
Date | bigint→stringrecursively through objects and arrays, leaving everything else unchanged (so for a typeXcontaining noDate/bigint,Transform<X>is structurally identical toX):For a deeply-nested compound type — recursion + arrays + an 8-member discriminated union with a shared base (
{base} & ({type:1;…} | {type:2;…} | …)) nested several levels behind arrays —tsgofails to proveTransformJson<X>assignable toXeven whenXhas noDate/bigint(i.e. when the transform is provably the identity):tscproves this assignable;tsgo(new builds) does not.Diagnosis / things tried (in case it helps narrow the regressed area)
From?" guard so the transform returnsBaseverbatim for no-Fromsubtrees → flips the failure intoTS2589"Type instantiation is excessively deep and possibly infinite" across the project, i.e. the extra recursive pass exhausts a depth/instantiation budget.{base} & unionintersection-with-union assignment.Reproduction note (the awkward part)
I could not reduce this to a small standalone repro: the minimal/standalone versions of the exact pattern (even with the same 8-member intersection-with-union behind arrays) compile clean under both tsgo and tsc. It only reproduces inside a large real project (many hundreds of interacting
Transform<…>instantiations across the program), which points at a scale-dependent / cumulative instantiation budget rather than a single-type defect.Happy to help bisect against the dev-build range, or to share a private reproduction with the team if that's an option.