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

TS 4.1 regression in type assertion of generic mapped type #41617

Closed
Igorbek opened this issue Nov 20, 2020 · 7 comments · Fixed by #41821
Closed

TS 4.1 regression in type assertion of generic mapped type #41617

Igorbek opened this issue Nov 20, 2020 · 7 comments · Fixed by #41821
Assignees
Labels
Bug A bug in TypeScript Domain: Conditional Types The issue relates to conditional types Fix Available A PR has been opened for this issue Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@Igorbek
Copy link
Contributor

Igorbek commented Nov 20, 2020

TypeScript Version: 4.1.2

Search Terms: CFA, narrowing, generic, mapped type, conditional type, type assertion

Code

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]>) {
  if (isA(a2)) {
    // a2 is not narrowed
    a2.x // error, but should be ok
  }
}

Expected behavior:

Type of a2 should be narrowed to ReturnType<T[M]> & A
It works this way in TS 4.0

Actual behavior:

Type of a2 remains only ReturnType<T[M]>

Playground Link: https://www.typescriptlang.org/play?ts=4.1.0-beta#code/JYOwLgpgTgZghgYwgAgILIN7IB4C5kgCuAtgEbTIC+AUNQCYQIA2cUKMhICYwA9iMmABnVAAo4+TgGsQvAO4gAlPjiChaANy0wATwAOKAGKdufEEIDypAFYAeACoA+ZAF5M1ZMgDaAaUECpCB1eGGR7AF18UUVXZ2lZBWoaag4uHn5kAHNbDzDkCGxIEDp1YzSzSxsHRwAaXIBZfMKIYvVA4ND7akdxACZ8ACUIMEIoEHt9CAcvevDHGIxc4FDRYTE4XsUF3M8NgDpsZAB6I-yoKF4oXJoaIA

@Igorbek Igorbek changed the title TS 4.1 regression in CFA of generic mapped type TS 4.1 regression in type assertion of generic mapped type Nov 20, 2020
@Igorbek
Copy link
Contributor Author

Igorbek commented 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 added the Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros label Nov 25, 2020
@orta
Copy link
Contributor

orta commented Nov 25, 2020

@typescript-bot run repros

@typescript-bot
Copy link
Collaborator

Heya @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
Copy link
Collaborator

typescript-bot commented 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 @Igorbek

❌ Failed: -

  • Property 'x' does not exist on type 'ReturnType<T[M]>'.

Comment by @weswigham

👍 Compiled

Historical Information

Issue body code block by @Igorbek

Version Reproduction Outputs
4.1.2, Nightly

❌ Failed: -

  • Property 'x' does not exist on type 'ReturnType<T[M]>'.

3.7.5, 3.8.2, 3.9.2, 4.0.2

👍 Compiled

Comment by @weswigham

Version Reproduction Outputs
Nightly

👍 Compiled

@RyanCavanaugh RyanCavanaugh added the Needs Investigation This issue needs a team member to investigate its status. label Dec 2, 2020
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.2.0 milestone Dec 2, 2020
@weswigham
Copy link
Member

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 run repros

@typescript-bot
Copy link
Collaborator

Heya @weswigham, I've started to run the code sample repros for you. Here's the link to my best guess at the log.

@weswigham weswigham added Bug A bug in TypeScript Domain: Conditional Types The issue relates to conditional types and removed Needs Investigation This issue needs a team member to investigate its status. labels Dec 4, 2020
@weswigham
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: Conditional Types The issue relates to conditional types Fix Available A PR has been opened for this issue Has Repro This issue has compiler-backed repros: https://aka.ms/ts-repros Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
7 participants