Skip to content

Type guard affects type of variable in surprising wayΒ #50916

Closed
@MichaelMitchell-at

Description

@MichaelMitchell-at

Bug Report

πŸ”Ž Search Terms

type guard / fall through / narrow / change / lazy / evaluate

πŸ•— Version & Regression Information

  • This changed between versions v4.7.4 and v4.8.2

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type Identity<T> = {[K in keyof T]: T[K]};

type Self<T> = T extends unknown ? Identity<T> : never;

function is<T>(value: T): value is Self<T> {
    return true;
}

type Union =  {a: number} | {b: number} | {c: number};

function example(x: Union) {
    if (is(x)) {}
    if (is(x)) {}
    if (is(x)) {}
    if (is(x)) {}
    if (is(x)) {}
    if (is(x)) {}
    if (is(x)) {}
    if (is(x)) {}

    return x;
    //     ^?
}

πŸ™ Actual behavior

The type of x is "narrowed" to Identity<Identity<Identity<Identity<Identity<Identity<Identity<Identity<{a: number;}>>>>>>>> | Identity<Identity<Identity<Identity<Identity<Identity<Identity<Identity<{b: number;}>>>>>>>> | Identity<Identity<Identity<Identity<Identity<Identity<Identity<Identity<{c: number;}>>>>>>>>

It's as if a variable gets narrowed to the union of the types of both sides of the type predicate, e.g.

if (isA(aOrB)) {
  // `aOrB` gets narrowed to `A`
} else {
  // `aOrB` gets narrowed to `Exclude<typeof aOrB, A>`
}

// `aOrB` gets narrowed to `A | Exclude<typeof aOrB, A>` but it should just be left alone

πŸ™‚ Expected behavior

The type of x doesn't change.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions