Description
TypeScript Version: 2.8.0-dev.20180204
Code
declare function broke(impossible: never): never; // used to ensure full case coverage
interface Foo { kind: 'foo'; }
declare function isFoo(foobar: Foo | Bar): foobar is Foo;
interface Bar { kind: 'bar'; }
declare function isBar(foobar: Foo | Bar): foobar is Bar;
function mapFooOrBar<FooBar extends Foo | Bar, R>(
foobar: FooBar,
mapFoo: FooBar extends Foo ? ((value: Foo) => R) : ((impossible: never) => never),
mapBar: FooBar extends Bar ? ((value: Bar) => R) : ((impossible: never) => never),
): R {
if (isFoo(foobar)) {
return mapFoo(foobar);
/* ^^^^^^^^^^^^^^
Cannot invoke an expression whose type lacks a call signature. Type '((value: Foo) => R) | ((impossible: never) => never)' has no compatible call signatures. */
}
else if (isBar(foobar)) {
return mapBar(foobar);
/* ^^^^^^^^^^^^^^
Cannot invoke an expression whose type lacks a call signature. Type '((value: Bar) => R) | ((impossible: never) => never)' has no compatible call signatures. */
}
else {
return broke(foobar as never);
}
}
(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.