Repository navigation
TS 4.1 regression in type assertion of generic mapped type #41617
Description
Activity
Igorbek commented on Nov 23, 2020
I tried to reduce the repro, but it reproduces only when all these present:
- conditional type that is being narrowed
ReturnType<> - generic mapped type that is constraints by itself
T extends FunctionsObj<T> - field accessed with generic type
T[M]
TypeScript Bot (@typescript-bot) run repros
typescript-bot commented on Nov 25, 2020
Heya Orta Therox (@orta), I've started to run the code sample repros for you. Here's the link to my best guess at the log.
typescript-bot commented on Nov 25, 2020
👋 Hi, I'm the Repro bot. I can help narrow down and track compiler bugs across releases! This comment reflects the current state of the 2 repros in this issue running against the nightly TypeScript.
Issue body code block by Igor Oleinikov (@Igorbek)
❌ Failed: -
Property 'x' does not exist on type 'ReturnType<T[M]>'.
👍 Compiled
Historical Information
Issue body code block by Igor Oleinikov (@Igorbek)
| Version | Reproduction Outputs |
|---|---|
| 4.1.2, Nightly |
❌ Failed: -
|
| 3.7.5, 3.8.2, 3.9.2, 4.0.2 |
👍 Compiled |
Comment by Wesley Wigham (@weswigham)
| Version | Reproduction Outputs |
|---|---|
| Nightly |
👍 Compiled |
Here's the problem, but without control flow involved:
interface A { x: number }
declare function isA(a: unknown): a is A;
type FunctionsObj<T> = {
[K in keyof T]: () => unknown
}
function g<
T extends FunctionsObj<T>,
M extends keyof T
>(a2: ReturnType<T[M]>, x: A) {
x = a2; // shouldn't be allowed, but is
}This is a bug in our subtyping rules, not control flow (which would undoubtedly be easier to fix).
TypeScript Bot (@typescript-bot) run repros
typescript-bot commented on Dec 4, 2020
Heya Wesley Wigham (@weswigham), I've started to run the code sample repros for you. Here's the link to my best guess at the log.
Looks like the root cause is our change in 4.1 to isDeeplyNestedType - it is now erroneously flagging a target side of the comparison, which doesn't change, as "deeply nested". Since the source side of the relation goes through about 6 transforms with the target side remaining unchanged, both sides get flagged as "deeply nesting", resulting in a Maybe result which eventually allows the assignment. I think this can be remedied by having separate source/target stack depths, so we don't increase the target stack depth when we're only transforming the source for a comparison.
TypeScript Version: 4.1.2
Search Terms: CFA, narrowing, generic, mapped type, conditional type, type assertion
Code
Expected behavior:
Type of
a2should be narrowed toReturnType<T[M]> & AIt works this way in TS 4.0
Actual behavior:
Type of
a2remains onlyReturnType<T[M]>Playground Link: https://www.typescriptlang.org/play?ts=4.1.0-beta#code/JYOwLgpgTgZghgYwgAgILIN7IB4C5kgCuAtgEbTIC+AUNQCYQIA2cUKMhICYwA9iMmABnVAAo4+TgGsQvAO4gAlPjiChaANy0wATwAOKAGKdufEEIDypAFYAeACoA+ZAF5M1ZMgDaAaUECpCB1eGGR7AF18UUVXZ2lZBWoaag4uHn5kAHNbDzDkCGxIEDp1YzSzSxsHRwAaXIBZfMKIYvVA4ND7akdxACZ8ACUIMEIoEHt9CAcvevDHGIxc4FDRYTE4XsUF3M8NgDpsZAB6I-yoKF4oXJoaIA