Description
π Search Terms
recursive mapped types, assignability, depth check, deeply nested
π Version & Regression Information
If this is in fact a bug, it looks like it was introduced in v4.5
- This can cause a runtime error when using incompatible values whose types are derived from recursive mapped types with more than 2 levels of nesting because the compiler seems to consider them equal (even when the derived type is fully instantiated (not infinite)).
- This changed between versions v4.4 and v4.5
β― Playground Link
π» Code
type Id<T> = { [K in keyof T]: Id<T[K]> }
type HasNumeric = Id<{ x: { y: { z: number } } }>
// ^? type HasNumeric = { x: { y: { z: number } } }
type HasString = Id<{ x: { y: { z: string } } }>
// ^? type HasString = { x: { y: { z: string } } }
const toDollarsAndCents = (_: HasNumeric): string => _.x.y.z.toFixed(2)
declare const illegalValue: HasString
// ^? const illegalValue: { x: { y: { z: string } } }
/** π΅ */
toDollarsAndCents(illegalValue)
π Actual behavior
I passed a value known by the compiler to be of type { x: { y: { z: string } } }
to a function expecting { x: { y: { z: number } } }
and did not get a compile time error warning me about it.
π Expected behavior
I expect to get a compile time error when I pass a value known by the compiler to be of type { x: { y: { z: string } } }
to a function expecting { x: { y: { z: number } } }
Additional information about the issue
Hey team! First of all, thank you for your work on this project. I have used TypeScript every day for years, and since the release of v5 in particular, saw a noticeable increase in my productivity at work :)
Regarding this issue, after further testing, it seems pretty trivial to reproduce with any recursive mapped type more than 2 levels deep (even with a "no-op" transformation, as is the case with Id
).
Even if the type were not fully instantiated, the assignability rules in this case seem to work exactly backwards from what I'd expect, which makes me think this might not be the intended behavior.
This issue might be related to #46599, which fits given that the playground's type-checker does complain in v4.4
Let me know if there's anything you'd like me to elaborate on!