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

Broken inferred recursive types #43817

Closed
blackakula opened this issue Apr 25, 2021 · 9 comments
Closed

Broken inferred recursive types #43817

blackakula opened this issue Apr 25, 2021 · 9 comments
Assignees
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@blackakula
Copy link

Bug Report

TypeScript inference on recursive types is broken since v4.1

πŸ”Ž Search Terms

  • inferred
  • recursive

πŸ•— Version & Regression Information

  • This changed between versions 4.0.5 and 4.1.5

⏯ Playground Link

Playground link with 4.3.0-beta - with the TS errors

Playground link with 4.0.5 - no errors

πŸ’» Code

const Builder = <T extends {}>(model: T) => ({
    withComment: (comment: string) => Builder({ ...model, comment }),
    withSpecialComment: () => Builder(model).withComment('Special comment'),
    withTrackingNumber: (tracking: number) => Builder({ ...model, tracking }),
    build: () => model })

const a = Builder({});
// a.withComment('test').build().tracking // OK - expected "Property 'tracking' does not exist on type '{ comment: string; }'""
console.log(a.withTrackingNumber(1234).withSpecialComment().build().tracking)

πŸ™ Actual behavior

TS compiler error: "The inferred type of this node exceeds the maximum length the compiler will serialize. An explicit type annotation is needed.(7056)"

πŸ™‚ Expected behavior

No errors on compilation

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Apr 26, 2021
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.4.0 milestone Apr 26, 2021
@weswigham
Copy link
Member

So, the declaration emit error is very intentional, because the declaration emit that is possible for us is imprecise:

image

see those anys? Yeah, those are places we just had to straight up truncate the type (if you click .d.ts on the sidebar in the 4.0.5 playground and way super patiently, you might eventually get what I have pictured above. or it might loop forever.). We don't really have a way to emit better declarations here without specifically generic inline type aliases, a la #30979

@weswigham weswigham added Design Limitation Constraints of the existing architecture prevent this from being fixed and removed Needs Investigation This issue needs a team member to investigate its status. labels Apr 26, 2021
@ahejlsberg
Copy link
Member

Below is a version with an explicit type annotation. This works as expected and generates a nice and compact declaration file.

type Builder<T> = {
    withComment: (comment: string) => Builder<T & { comment: string }>,
    withSpecialComment: () => Builder<T & { comment: string }>,
    withTrackingNumber: (tracking: number) => Builder<T & { tracking: number }>,
    build: () => T
};

const Builder: <T extends {}>(model: T) => Builder<T> = <T extends {}>(model: T) => ({
    withComment: (comment: string) => Builder({ ...model, comment }),
    withSpecialComment: () => Builder(model).withComment('Special comment'),
    withTrackingNumber: (tracking: number) => Builder({ ...model, tracking }),
    build: () => model });

const a = Builder({});

@SephReed
Copy link

Currently running into this issue.

I find that everything is fine until this error comes up, then suddenly the entire language server starts taking 3-6 seconds to respond to anything.

Unfortunately, It's very, very much impossible for me to give "An explicit type annotation is needed."

Also, everything was working fine this morning, and I can't seem to figure out what has changed since then. So I know TS can do it.

I even have a demo within my installed project that works great, but converting it to an npm package appears to have made the recursion too much somehow.

@SephReed
Copy link

I made some progress on this issue by converting all my interfaces to abstract classes. Not sure why it worked, but you can read more here:

https://stackoverflow.com/a/68475392/4808079

@blackakula
Copy link
Author

Closing this issue without a fix - means breaking backward compatibility in a minor version.
Just checked in 4.4.0-beta - still this error

@mxxnseat
Copy link

mxxnseat commented Sep 6, 2021

i have same issue with mongoose when i try update my document with error text:
Type instantiation is excessively deep and possibly infinite.

Product.findOneAndUpdate(
            { id: product.id },
            {
                ...product,
                productCategoryId: categoryId,
                parentGroup: groupId,
            },
            { new: true, upsert: true }
        )

@SephReed
Copy link

I haven't shared it in this thread, but one fix I found is to use abstract classes instead of interfaces in certain areas.

I have no idea why this works, but an abstract class that references itself is much happier than an interface that does. Worked for me at least...

@zomars
Copy link

zomars commented Feb 19, 2022

This issue just started popping up without any changes made to our project.

@Qix-
Copy link

Qix- commented Aug 15, 2022

This is happening with AJV schemas (trivial ones at that), but only in my editor. The actual tsc invocation works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

9 participants