Skip to content

Suggestion: Type narrowing also narrows conditional types#21879

@krryan

Description

@krryan

TypeScript Version: 2.8.0-dev.20180204

Code

declarefunctionbroke(impossible: never): never;// used to ensure full case coverageinterfaceFoo{kind: 'foo';}declarefunctionisFoo(foobar: Foo|Bar): foobar is Foo;interfaceBar{kind: 'bar';}declarefunctionisBar(foobar: Foo|Bar): foobar is Bar;functionmapFooOrBar<FooBarextendsFoo|Bar,R>(foobar: FooBar,mapFoo: FooBarextendsFoo ? ((value: Foo)=>R) : ((impossible: never)=>never),mapBar: FooBarextendsBar ? ((value: Bar)=>R) : ((impossible: never)=>never),): R{if(isFoo(foobar)){returnmapFoo(foobar);/* ^^^^^^^^^^^^^^Cannot invoke an expression whose type lacks a call signature. Type '((value: Foo) => R) | ((impossible: never) => never)' has no compatible call signatures. */}elseif(isBar(foobar)){returnmapBar(foobar);/* ^^^^^^^^^^^^^^Cannot invoke an expression whose type lacks a call signature. Type '((value: Bar) => R) | ((impossible: never) => never)' has no compatible call signatures. */}else{returnbroke(foobarasnever);}}

(the casting foobar as never for the broke function is a workaround for #20375)

Expected Behavior
Compile without errors.

Actual Behavior
The types of mapFoo and mapBar are not reconsidered in light of passing the typeguard:
Cannot invoke an expression whose type lacks a call signature. Type '((value: Foo) => R) | ((impossible: never) => never)' has no compatible call signatures.

Cannot invoke an expression whose type lacks a call signature. Type '((value: Bar) => R) | ((impossible: never) => never)' has no compatible call signatures.

My use case for this is a situation where I have a union of three types, but some cases will only ever use a union of two of those types. I want this kind of utility function to be re-usable for those situations, but indicate that the handlers for unincluded cases will never be called (and allow us to type-safely stub those branches, e.g. with that broke function).

Our project uses these kinds of unions and utility functions a lot and this would significantly improve them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions