Errors in @types/jsdom, @sinclair/typebox
- Node
v20.19.2on mac - Works fine with
tscfrom[email protected] - Errors visible with
@typescript/[email protected] - Dependency chain
[email protected]@types/[email protected]@sinclair/[email protected]
npx tsgo src
node_modules/@sinclair/typebox/typebox.d.ts:137:63 - error TS2321: Excessive stack depth comparing types 'UnionToTuple<{ [K in T]: TLiteral<K>; }[T], UnionLast<{ [K in T]: TLiteral<K>; }[T]>>' and 'TSchema[]'.
137 export type TExcludeTemplateLiteralResult<T extends string> = TUnionResult<Assert<UnionToTuple<{
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
138 [K in T]: TLiteral<K>;
~~~~~~~~~~~~~~~~~~~~~~~~~~
139 }[T]>, TSchema[]>>;
~~~~~~~~~~~~~~~~~~
node_modules/@sinclair/typebox/typebox.d.ts:145:63 - error TS2321: Excessive stack depth comparing types 'UnionToTuple<{ [K in T]: TLiteral<K>; }[T], UnionLast<{ [K in T]: TLiteral<K>; }[T]>>' and 'TSchema[]'.
145 export type TExtractTemplateLiteralResult<T extends string> = TUnionResult<Assert<UnionToTuple<{
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
146 [K in T]: TLiteral<K>;
~~~~~~~~~~~~~~~~~~~~~~~~~~
147 }[T]>, TSchema[]>>;
~~~~~~~~~~~~~~~~~~
node_modules/@sinclair/typebox/typebox.d.ts:380:102 - error TS2321: Excessive stack depth comparing types 'UnionToTuple<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>' and 'TLiteral<TLiteralValue>[]'.
380 export type TUnionTemplateLiteral<T extends TTemplateLiteral, S extends string = Static<T>> = Ensure<TUnionResult<Assert<UnionToTuple<{
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
381 [K in S]: TLiteral<K>;
~~~~~~~~~~~~~~~~~~~~~~~~~~
382 }[S]>, TLiteral[]>>>;
~~~~~~~~~~~~~~~~~~~
node_modules/@types/jquery/misc.d.ts:7359:14 - error TS2717: Subsequent property declarations must have the same type. Property 'toStringTag' must be of type 'unique symbol', but here has type 'symbol'.
7359 readonly toStringTag: symbol;
~~~~~~~~~~~
node_modules/@typescript/native-preview-darwin-arm64/lib/lib.es2015.symbol.wellknown.d.ts:74:14 - 'toStringTag' was also declared here.
74 readonly toStringTag: unique symbol;
~~~~~~~~~~~
node_modules/@types/jsdom/base.d.ts:194:18 - error TS2411: Property 'Infinity' of type 'number' is not assignable to 'number' index type 'Window'.
194 readonly ["Infinity"]: number;
~~~~~~~~~~~~
node_modules/@types/jsdom/base.d.ts:195:18 - error TS2411: Property 'NaN' of type 'number' is not assignable to 'number' index type 'Window'.
195 readonly ["NaN"]: number;
~~~~~~~
Found 6 errors in 3 files.
Errors Files
3 node_modules/@sinclair/typebox/typebox.d.ts:137
1 node_modules/@types/jquery/misc.d.ts:7359
2 node_modules/@types/jsdom/base.d.ts:194
Can you provide a short repro?
Here's a minimal reproduction:
https://github.com/andyfleming/repro-for-typescript-go-929
@andyfleming u might have forgotten to push some files there
@andyfleming u might have forgotten to push some files there
@Andarist A fresh clone of that repository and running the commands in the README reproduces the errors for me.
That's not what it was asked for here. A short repro would be a self-isolated one, preferably within a single file. It shouldn't rely on massive external packages
@Andarist @jakebailey Hello,
I have just happened across this issue. As per request, I have setup a repro specifically for TypeBox at the link below:
https://github.com/sinclairzx81/typescript-go-issue-929
I should note that the referenced TypeBox version 0.27.8 is extremely out of date. The issue can be resolved by updating TypeBox to the latest 0.34.33. Unfortunately, there is a very long tail of downstream libraries and tools that do take a dependency on older versions of Jest (which in turn take the dependency to 0.27.8). Given the dependency chains downstream, it's not entirely trivial for applications to just update to the latest versions to leverage TS native.
Happy to provide additional information if required. S
The best thing you could provide is a self-isolated repro of the problem. This one still depends on an external library, one that has a lot of unrelated (to the problem) types in it. Investigating such repro takes considerably more time than investigating a small one.
The best thing you could provide is a self-isolated repro of the problem. This one still depends on an external library, one that has a lot of unrelated (to the problem) types in it. Investigating such repro takes considerably more time than investigating a small one.
@Andarist Project has been updated to include only offending types. Library dependencies have been removed as per request.
https://github.com/sinclairzx81/typescript-go-issue-929
This is great and way more actionable. Thanks ❤ I'll investigate this in the coming days
My preliminary findings...
This is a type ordering issue. The type arguments are being normalized and thus simplified. getTrueTypeFromConditionalType in getSimplifiedConditionalType leads to relating [...UnionToTuple<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<...>>>>, UnionLast<...>] source to TLiteral<string>.
Here: https://github.com/microsoft/typescript-go/blob/9cf6764c67542f4b764d227d5195cdf348a03702/internal/checker/relater.go#L3779
We can observe:
source // [...UnionToTuple<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<...>>>>, UnionLast<...>]
target // TLiteral<string>[]
And we enter isRelatedTo with their index info types:
originalSource // UnionLast<{ [K in S]: TLiteral<K>; }[S]> | UnionToTuple<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>[number]
originalTarget // TLiteral<string>
Buuut... in Corsa the order of this originalSource union is flipped. This ends up in eachTypeRelatedToType and the whole relation ends up returning Ternary.False (in Strada too) but in Corsa it relates against the first constituent, well, first. That leads to deep recursion when the constraint of this source gets related here:
https://github.com/microsoft/typescript-go/blob/9cf6764c67542f4b764d227d5195cdf348a03702/internal/checker/relater.go#L3608-L3609
We can observe there:
source // UnionToTuple<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>[number]
constraint // ([] | [...UnionToTuple<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>, UnionLast<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>])[number]
target // TLiteral<string>
When the compiler hits it again those can be observed:
source // UnionToTuple<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>, UnionLast<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>>>[number]
constraint // ([] | [...UnionToTuple<Exclude<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>, UnionLast<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>>>, UnionLast<Exclude<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>, UnionLast<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>>>>>, UnionLast<Exclude<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>, UnionLast<Exclude<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>>>>])[number]
target // TLiteral<string>
As we can see, the source side here just "grows" through recursive attempts at relating its constraint to the target.
So, in a sense, Strada was able to return early from this as it related a different source first. Note that all of this is just within the normalization/simplification of the source. It can't be simplified - but it has to relate types to check if it can or not. And that leads to the dreaded "Excessive stack depth comparing types"
Unfortunately this is only getting worse becuase @jest/schemas depends on @sinclair/typebox and so now any project using jest fails without skipLibCheck from:
node_modules/.pnpm/@[email protected]/node_modules/@sinclair/typebox/typebox.d.ts:380:102 - error TS2321: Excessive stack depth comparing types 'UnionToTuple<{ [K in S]: TLiteral<K>; }[S], UnionLast<{ [K in S]: TLiteral<K>; }[S]>>' and 'TLiteral<TLiteralValue>[]'.
380 export type TUnionTemplateLiteral<T extends TTemplateLiteral, S extends string = Static<T>> = Ensure<TUnionResult<Assert<UnionToTuple<{
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
381 [K in S]: TLiteral<K>;
~~~~~~~~~~~~~~~~~~~~~~~~~~
382 }[S]>, TLiteral[]>>>;
~~~~~~~~~~~~~~~~~~~
I hit this while testing build mode in DefinitelyTyped-tools.