Skip to content

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

Description

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

Activity

changed the title [-]TS 4.1 regression in CFA of generic mapped type[/-] [+]TS 4.1 regression in type assertion of generic mapped type[/+] on Nov 20, 2020

Igorbek commented on Nov 23, 2020

@Igorbek
ContributorAuthor

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]

orta commented on Nov 25, 2020

@orta
Contributor

typescript-bot commented on Nov 25, 2020

@typescript-bot
Contributor

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

@typescript-bot
Contributor

👋 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]>'.

Comment by Wesley Wigham (@weswigham)

👍 Compiled

Historical Information

Issue body code block by Igor Oleinikov (@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 Wesley Wigham (@weswigham)

Version Reproduction Outputs
Nightly

👍 Compiled

weswigham commented on Dec 4, 2020

@weswigham
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 (@typescript-bot) run repros

typescript-bot commented on Dec 4, 2020

@typescript-bot
Contributor

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.

added
BugA bug in TypeScript
and removed
Needs InvestigationThis issue needs a team member to investigate its status.
on Dec 4, 2020

weswigham commented on Dec 4, 2020

@weswigham
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.

locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptDomain: Conditional TypesThe issue relates to conditional typesFix AvailableA PR has been opened for this issueHas ReproThis issue has compiler-backed repros: https://aka.ms/ts-reprosRescheduledThis issue was previously scheduled to an earlier milestone

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions