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

Discriminated union narrowed incorrectly by user-defined type predicate #40035

Closed
jamesjuett opened this issue Aug 13, 2020 · 2 comments · Fixed by #49625
Closed

Discriminated union narrowed incorrectly by user-defined type predicate #40035

jamesjuett opened this issue Aug 13, 2020 · 2 comments · Fixed by #49625
Labels
Duplicate An existing issue was already created

Comments

@jamesjuett
Copy link

TypeScript Version: 4.0.0-dev.20200803

Search Terms:
discriminated union
union
type predicate
type guard
narrow

Code

interface A {
    kind: "A";
    foo?: string;
}

interface AA extends A {
    foo: string;
}

interface B {
    kind: "B";
    foo: string;
}

interface BB extends B {
    //blah: string; // comment or uncomment this line
}

function isDefiniteFoo(x: A | B) : x is AA | BB {
    return !!x.foo;
}


let x!: A | B;
if (isDefiniteFoo(x)) {
    // Without line 16, the type of x is narrowed to B
    // If line 16 is present, the type of x is narrowed to AA | BB
    let z = x;

    // Note that BB isn't required to expose the bug. If the return type on
    // isDefiniteFoo is : x is AA | B, x is still narrowed to B rather than AA | B
}

Expected behavior:
The type of x should be narrowed to AA | BB.

Actual behavior:
The type of x is narrowed to B.

Playground Link:
https://www.typescriptlang.org/play?ts=4.0.0-dev.20200803#code/JYOwLgpgTgZghgYwgAgILIN4Chm+Qa1ABMAuZAIlXIG4c8YB7BgfjIGcwpQBzWgXyxZQkWIhSp0EAB6QQRNmkx1cjBu049+g4dHhJkAISV4CxMuQM1lyVeq4heWAUPC6xho9NnzDxvAHp-ACMAGzgACztNZEDkBAYAWwSIcGQGKGQAVxB4pJSwZDBw4AUQ0AgnQRhshDBgBhBkEoARCBhQYEgAMSYACikydAAfQwBKZDIpJoUJZBGDI2wTKAgwTKhGgEJNqQA6VS1BENXkKU3BucNaYBhkXpa2ju6+qVHxpYD-ZAB1TvCGTIFMogFAARgAbAAaQrhFBgACeAAcUAxblMSsgQHAoFAGAB3CBEQoMQzWWIASVuwLB4OmyERKzY+WhRThSJRaLpWJx+MJxLQww81mOBQAXsgALynWhkr4AOQYkBhcAKC2mIAA5AUVgBHTLAFZEsAk6SIhhMmEoIKZbi7ZCUy3IFZrDaFdlpECy6atdogToQHokjGTOmzebQ9EKDjAEIhTHY3EEo0koxQFWwjJFOCNMOkvhAA

@jack-williams
Copy link
Collaborator

jack-williams commented Aug 13, 2020

This looks to be a duplicate of #31156.

A is not assignable to AA | BB therefore it gets filtered out by the type predicate.
B is assignable to AA | BB (without line 16) and is therefore retained by the type predicate.

With line 16, neither are related so it falls back to full check where AA | BB is a subtype of A | B, so that is the result of the predicate.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Aug 19, 2020
@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
4 participants