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

Type variables in type abstractions are not properly concretized #61041

Open
mame opened this issue Jan 24, 2025 · 2 comments
Open

Type variables in type abstractions are not properly concretized #61041

mame opened this issue Jan 24, 2025 · 2 comments
Assignees
Labels
Bug A bug in TypeScript

Comments

@mame
Copy link

mame commented Jan 24, 2025

πŸ”Ž Search Terms

type variables unknown

πŸ•— Version & Regression Information

  • This changed between versions 4.9.5 and 5.0.4.

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.7.3#code/MYewdgzgLgBAZjAvDAPADQDQD4AUBzALlQEFscAjItASiSxkxgitsXrxwmoG4AoX0JFgAnAKaxkcHCgBCZAB5EZregEYMMAETRhmnrwD0BmCZgA9APxA

πŸ’» Code

const f = <X,>(g: <A,>(b: X) => X, s: X) => g(s);

const ret = f(<B,>(x: B) => 1, "str");
//    ^? const ret: unknown

πŸ™ Actual behavior

No type error is reported and ret is inferred as unknown type.

πŸ™‚ Expected behavior

I think a type error is reported because the call to f attempts to concretize the type variable X not only as a number but also as a string. In fact, TypeScript 4.9.5 reported a type error.

Additional information about the issue

I am not sure that TypeScript 4.9.5 was perfect. The following code is inferred to be unknown, but I think string is correct. This behavior was back to TypeScript 3.5.1.

const f = <X,>(g: <A,>(b: X) => X, s: X) => g(s);

const ret = f(<B,>(x: B) => x, "str");
//    ^? const ret: unknown

// actual: ret is inferred as unknown
// expected: ret is inferred as string

https://www.typescriptlang.org/play/?ts=5.7.3#code/MYewdgzgLgBAZjAvDAPADQDQD4AUBzALlQEFscAjItASiSxkxgitsXrxwmoG4AoX0JFgAnAKaxkcHCgBCZAB5EZrevIwwARNGEaevAPT6YxmAD0A-P0MwAhsCgBXGwBsiY2AEsIMD2DijhMQATW28HMABrMBAAdzADI1F5AAdRe1Egt3Efb19-QIzQpihhXzwgA

I also found a strange behavior that a type variable that should have been concretized was returned without being concretized. I thought this is related, but I could be wrong. Sorry if so.

const f = <X,>(g: <A,>(x: X) => X) => g<string>;

const h = f<number>(<B,>(x: number) => 1);
//    ^? const h: (x: X) => X

h(1);
// actual: type error
// expected: no type error

https://www.typescriptlang.org/play/?ts=5.7.3#code/MYewdgzgLgBAZjAvDAPADQDQD4AUBzALlQEFscAPItASiSxhrpjxWgCcBLMPLAbgCh+oSLAAWSeCjABXALYAjAKZtcKAEJlKMGQuW1E9AIzUBAelMxLMAHoB+QaJzGzFgIbAo01wBsiUAJ4ADoowymwgbPzmoeTBHooAJkRgIDABwaFs4WxAA

@jcalz
Copy link
Contributor

jcalz commented Jan 24, 2025

The first issue could presumably be dealt with by using NoInfer to stop TS from trying to use g for inference there:

const f = <X,>(g: NoInfer<<A,>(b: X) => X>, s: X) => g(s);

or

const f = <X,>(g: <A,>(b: X) => NoInfer<X>, s: X) => g(s);

The second issue looks to me like a genuine bug with instantiation expressions (reminds me of #55467 and the like, but πŸ€·β€β™‚οΈ)

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Jan 24, 2025
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 5.8.0 milestone Jan 24, 2025
@RyanCavanaugh
Copy link
Member

Agree with @jcalz on both counts; the first example is too abstracted to make a particular lot of sense of and NoInfer is likely the best we can do.

The second example leaks a type parameter, e.g. this produces an invalid declaration file, which is always a bug

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

No branches or pull requests

4 participants