Skip to content

Incorrect type checking (maybe?) for recursive types #61520

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

Closed
e965 opened this issue Apr 1, 2025 · 4 comments
Closed

Incorrect type checking (maybe?) for recursive types #61520

e965 opened this issue Apr 1, 2025 · 4 comments
Labels
Not a Defect This behavior is one of several equally-correct options

Comments

@e965
Copy link

e965 commented Apr 1, 2025

πŸ”Ž Search Terms

"recursive"

πŸ•— Version & Regression Information

Typescript 5.7.3, but on the current version in the sandbox (5.8.2) it reproduces too

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.8.2#code/C4TwDgpgBAShDGBXATgZwJYDcIBVzQF4oBvAKCigDN0IAbAEwH4AuKAO0QFsAjCZAbnJQA8jBawEKDNjyQA2gF1BAX0Gl4AezapgVdGmCsAFAEooBAHwSkaLLnzmop81aNkKFAPSeoqABYaiAxQvFB8yBrIVJFQwH7QqAha9AA0IYi6cXzQ6KjsGmHIEchCFKKscsR6dPSsAIxQymlVAIbc8KwATI0KKaUeA4OD3lAAemMT41OkyiZqmtq61AYAwpHICIZOZpbWUnayhNuscDbS9pAuTu4eI9wZUADu6HFhAB5gtOjwL1AbwCg2LEHPQELQWsgWsB0FooL94PF4ABrPKaIqbWggfrlKCVaoMeqNZpQNodKDdZS9fpDGm3HxTSaTGZzIA

πŸ’» Code

type RecursiveType = {
  field?: number;
  OR?: RecursiveType[];
};

const first: () => RecursiveType = () => ({
    // should be error for the second, but there is no error
    OR: [{ field: 1 }, { abc: 2 }],
                    // ^ ^ ^ ^ ^ ^
});

const firstCorrect: () => RecursiveType = (): RecursiveType => ({
    // but with explicit return type declaration it checks correctly
    OR: [{ field: 1 }, { abc: 2 }],
                    // ^ ^ ^ ^ ^ ^
});

πŸ™ Actual behavior

Only the second example throws an error

πŸ™‚ Expected behavior

Both examples should throw an error

Additional information about the issue

This is probably ACTUALLY correct behavior, but I still decided to create a bug report just in case

@e965 e965 changed the title Incorrect type checking for recursive types (maybe?) Incorrect type checking (maybe?) for recursive types Apr 1, 2025
@MartinJohns
Copy link
Contributor

MartinJohns commented Apr 1, 2025

Working as intended. The return type to your function is inferred based on the returned value, not on the type of the variable you assign it to. Then on the second round it checks assignability, and the types are compatible so there's no error. It's allowed to have additional properties.

There's a bunch of duplicates of this on the tracker, e.g. #59586.

@Andarist
Copy link
Contributor

Andarist commented Apr 2, 2025

You are totally right that this is a fallout of how things work currently. But this issue here is quite specific so I wouldn't call it a hard duplicate of the referenced issue (yet?).

The problem with this is that the return type "suffers" from object literal unification~ (introduced in TS 2.7 by this PR) but at the same time, the contextual type for that array element is a weak type. Even though extra properties are allowed there (as explained by you) - that type is only compatible with the weak type target because of that object literal unification. Without it, it wouldn't be.

@e965
Copy link
Author

e965 commented Apr 2, 2025

The funniest thing for me is that exactly the same .d.ts is generated for both expressions (as it should be), but the behavior is different

Image

@nmain
Copy link

nmain commented Apr 2, 2025

but the behavior is different

From a typing perspective, it's not. Any object type can always have excess properties on it at runtime. It'd be nice to have the excess property checks lint here, but it's still just a lint.

@RyanCavanaugh RyanCavanaugh added the Not a Defect This behavior is one of several equally-correct options label Apr 2, 2025
@e965 e965 closed this as completed Apr 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Not a Defect This behavior is one of several equally-correct options
Projects
None yet
Development

No branches or pull requests

5 participants