Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TS 4.5: Type instantiation is excessively deep and possibly infinite. #120

Closed
gmaclennan opened this issue Nov 18, 2021 · 13 comments
Closed

Comments

@gmaclennan
Copy link

I know this has already had a quick fix via #119 but with @sinclair/[email protected] I still get this error for this very basic code:

import { Static, Type as T } from "@sinclair/typebox";
import got from "got";

const MySchema = T.Object({
  name: T.String(),
});

type MyType = Static<typeof MySchema>;

async function getThing(id: string): Promise<MyType> {
  const url = `https://example.com/myThing.json`;
  return await got(url).json();
}

async function getAllThings(ids: string[]): Promise<MyType[]> {
  return await Promise.all(ids.map((id) => getThing(id)));
}

Error returned:

> tsc --noEmit

index.ts:16:16 - error TS2589: Type instantiation is excessively deep and possibly infinite.

16   return await Promise.all(ids.map((id) => getThing(id)));
                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Minimal repro here: https://github.com/gmaclennan/typebox-error-repro

Error running on CI: https://github.com/gmaclennan/typebox-error-repro/runs/4251888078?check_suite_focus=true

For what it's worth, I checked with other version of Typebox, and this code compiles with v0.11.0 but fails on any later version including v0.20.6

@stevejhiggs
Copy link

I also have issues with this even in 0.20.6. My repro is at https://replit.com/@SteveHiggs/GrumpyQuizzicalFields

gmaclennan added a commit to digidem/mapeo-map-server that referenced this issue Nov 18, 2021
@sinclairzx81
Copy link
Owner

@gmaclennan @stevejhiggs Thanks for reporting. Just taking a deeper look into this now. It looks like there's been fairly significant changes in 4.5. I'm guessing this is probably related to the following microsoft/TypeScript#46429.

I'll start looking at a patch within the next few days.
Cheers
S

@gmaclennan
Copy link
Author

Thanks @sinclairzx81. Sticking to Typescript 4.4 keeps everything working for now :)

@StCatfish
Copy link

StCatfish commented Nov 18, 2021

The simplest build I came up with:
Versions:

{
    "@sinclair/typebox": "0.20.6",
    "typescript": "4.5.2"
 }
import {
  Static,
  TSchema,
} from '@sinclair/typebox';

export function validate<ResponseSchema extends TSchema>(
  data: Static<ResponseSchema>
): Static<ResponseSchema> {
  return data;
}

tsc yields an error:

index.ts:9:10 - error TS2589: Type instantiation is excessively deep and possibly infinite.

9   return data;
           ~~~~


Found 1 error.

@sinclairzx81
Copy link
Owner

@gmaclennan Have published an update on @sinclair/[email protected] which should resolve these issues. The update reinstates the constructor and function arguments, as well as applies a few upstream updates I had been meaning to look at. I have dropped a few notes on the changelog which you can read about here.

These updates are fairly sweeping type inference changes to accommodate these new 4.5 constraints, but these updates should also work in previous revisions of the compiler, have tested back to the minimum version of TS 4.3.5 and things should be ok.

Let me know if you run into any problems
Cheers

@stevejhiggs
Copy link

Can confirm that 0.21.0 fixes all the issues I was having. Amazing work, thanks!

@leoyli-headsup
Copy link

Amazing, much appreciated!

@sinclairzx81
Copy link
Owner

Cheers everyone :) Will close off this issue. Thanks for letting me know!

@ayZagen
Copy link

ayZagen commented Apr 22, 2023

I know this issue is old and I don't have problems using with typescript 5 but this error happens when I try to rollup types with api-extractor which is using bundled ts with version 4.8.4.

@sinclairzx81 Do you have any tips or solution regarding this?

Warning: node_modules/.pnpm/@[email protected]/node_modules/@sinclair/typebox/typebox.d.ts:110:47 - (TS2589) Type instantiation is excessively deep and possibly infinite.

@sinclairzx81
Copy link
Owner

@ayZagen Hi,

Looking at the line number, it appears to be related to TComposite which is an extremely complicated type. I'm actually trying to get rid of this type (as it's provided for backwards compatibility) but to implement the type correctly, TypeScript needs to perform backflips to infer it. It should be supported in TS 4.2.3 and above, but depending on how complicated your type is, mileage may vary.

If possible, you can use Type.Intersect() over Type.Composite(). The difference between these types is that Type.Intersect() doesn't try to combine the composed types into a singular object (which is a lot more TS friendly). Alternatively you can upgrade to TS 5.0.

Repro

Would it be possible to share a repro of the Type you're having problems with? You should be able post it up on the TypeScript Playground and repro by setting the compiler version to 4.8.4. I'm interested in taking a look.

Hope this helps
S

@sinclairzx81
Copy link
Owner

@ayZagen Quick code paste for TS 4.8.4. Can't trivially replicate the issue but still interested to trace down the cause from the types you have.

Example

The following example intersects 3 objects with overlapping properties. The overlapping properties are combined into a distributed TIntersect (where each property infers to never, which is expected). This type pushes inference harder than usual as the work to produce the intersection per property is N^2 (3 properties * 3 intersections). It might be possible to explode the inference by having a lot of overlapping properties, so you may wish to check for this in your implementation.

TypeScript Link Here

import { Type, Static } from '@sinclair/typebox'

type T = Static<typeof T>      // type T = { x: never, y: never, z: never }

const T = Type.Composite([     // const T: TObject<{
    Type.Object({              //   x: TIntersect<[TNumber, TString, TBoolean]>, - (TNever)
      x: Type.Number(),        //   y: TIntersect<[TNumber, TString, TBoolean]>, - (TNever)
      y: Type.Number(),        //   z: TIntersect<[TNumber, TString, TBoolean]>, - (TNever)
      z: Type.Number(),        // }>
    }),
    Type.Object({ 
      x: Type.String(),
      y: Type.String(),
      z: Type.String(),
    }),
    Type.Object({ 
      x: Type.Boolean(),
      y: Type.Boolean(),
      z: Type.Boolean(),
    }),
])

@ayZagen
Copy link

ayZagen commented Apr 23, 2023

@sinclairzx81 Thanks for the detailed responses! Strangely though I tried downgrading to 4.8.4 in the project itself and had no issues with it. It only happens when using api-extractor. BTW I tried removing Composite types but api-extractor fails when trying to inline typebox. I believe this issue is specific to api-extractor.

Now I am using dts-bundle-generator and have no issues.

Thanks.

@Abe27342
Copy link

Abe27342 commented Apr 27, 2023

Adding this here as another datapoint in case it's helpful for others--I encountered a similar issue to @ayZagen in a project using Typescript 4.5.5 and api-extractor. We're invoking api-extractor with the --typescript-compiler-folder option which seems like it should internally use 4.5.5, but when doing some local debugging I'm not confident that's actually the case: it looked like api-extractor may have still been using the bundled 4.8.4 version as in the above reproduction.

I agree with the suspicion that it's specific to api-extractor. One interesting thing to note that the types I exported don't reference TComposite at all; I'm not sure why tsc would be trying to instantiate it.

Anyway, this isn't too rough for my use case as I'd rather not have typebox schemas in my public API anyway: the only reason they were there in the first place is because of this api-extractor issue: microsoft/rushstack#3616.

If someone else encounters this and needs to dig deeper, this should be the compiler API invocation which causes these errors in API-extractor: https://github.com/microsoft/rushstack/blob/c31f6c5be835823dfd9004d721f9fc89dca4945d/apps/api-extractor/src/collector/Collector.ts#L195.

Edit: Curiosity got the better of me on the version mismatch. With respect to API extractor seemingly using 4.8.4 when --typescript-compiler-folder is specified, the doc I linked above isn't particularly clear with what that option does. Its CLI doc here makes it more clear this only affects the system typings, which matches the code here. So it seems like expected behavior that api-extractor can only use the typescript version being bundled.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants