Skip to content

Different narrowing behaviour of user-defined type guards vs discriminated unions #10145

Closed
@yortus

Description

@yortus

TypeScript Version: nightly (2.1.0-dev.20160804)

Code

interface A { type: 'A' }
interface B { type: 'B' }

function isA(x: A|B): x is A { return x.type === 'A'; }
function isB(x: A|B): x is B { return x.type === 'B'; }

// Using if/else with type guard functions
function foo1(x: A|B): any {
    x // x is A | B
    if (isA(x)) {
        return x; // x is A
    }
    x // x is B |
    if (isB(x)) {
        return x; // x is B
    }
    x // x is B, but should be never                    <===== (1)
}

// Using if/else with discriminated unions
function foo2(x: A|B): any {
    x // x is A | B
    if (x.type === 'A') {
        return x; // x is A
    }
    x // x is B
    if (x.type === 'B') {
        return x; // x is B
    }
    x // x is never                                     <===== (2)
}

Expected behavior:
x is narrowed to never at both (1) and (2)

Actual behavior:
x is narrowed to never at (2), but at (1) it is narrowed to B.

Notes:
This is carried over from #9260 which is closed. See #9260 (comment)

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions