Always assigning to an un-initialized variable in an exhaustive switch
apexskier opened this issue ยท 3 comments
TypeScript Version: 3.4.0-dev.20190220
Search Terms:
switch case exhaustive assignment assign undefined TS2322
Code
Compile with the flags --noImplicitReturns --noImplicitAny --strictNullChecks
enum Test {
A,
B,
C
}
// this example correctly understands that all possible values of t are handled
function foo(t: Test): number {
switch (t) {
case Test.A:
return 1;
case Test.B:
return 2;
case Test.C:
return 3;
}
}
// this should be identical to foo, since a is always assigned as the switch is exhaustive
function bar(t: Test): number {
let a;
switch (t) {
case Test.A:
a = 1;
case Test.B:
a = 2;
case Test.C:
a = 3;
}
return a; // I don't expect an error here
}
Expected behavior:
Code compiles with no errors. When a
is returned in bar
, its type is number
. Typescript understands that an exhaustive switch with each case assigning to a type-inferred variable means that the variable's type is the union of each assigned value's type. I'd expect this to work because returns within an exhaustive switch are understood in a similar manner.
Actual behavior:
When a
is returned in bar
, its type is number | undefined
TS2322: Type 'number | undefined' is not assignable to type 'number'.
Type 'undefined' is not assignable to type 'number'.
Playground Link:
link here
Turn on noImplicitReturns
, noImplicitAny
, and strictNullChecks
.
Related Issues:
Comments in #18362 still apply. We have some special-casing we're capable of doing for return
, but it doesn't generalize to assignments.
how is it not covered by officially recommended:
function noMore(_: never): never { throw new Error('Boom!'); }
// this should be identical to foo, since a is always assigned as the switch is exhaustive
function bar(t: Test): number {
let a;
switch (t) {
case Test.A:
a = 1;
break;
case Test.B:
a = 2;
break;
case Test.C:
a = 3;
break;
default: return noMore(t);
}
return a; // <-- works
}
?