TypeScript Version: 2.9.0-dev.20180420
Search Terms: discriminated generic enum switch
Code
enum MyEnum {
ONE = 'one',
TWO = 'two',
}
interface TypeMap {
[MyEnum.ONE]: number;
[MyEnum.TWO]: string;
}
function doAction<T extends MyEnum>(type: T, value: TypeMap[T]): void {
switch (type) {
case MyEnum.ONE:
console.log('type:', type, ', value:', value);
break;
case MyEnum.TWO:
console.log('type:', type, ', value:', value);
break;
default:
console.log('type:', type, ', value:', value);
break;
}
}
Expected behavior: the types of type would correspond to MyEnum.ONE / MyEnum.TWO depending on the case, and thus value would also get the expected type.
Actual behavior:: type is still T extends MyEnum even within the discriminated switch statement.
Playground Link: TS Playground
Related (I think): #21483
T extends MyEnum is the right type. T is still generic, and in the presence of intersection type, a type can be manufactured that is more specific than MyEnum to instantiate your function with, e.g. MyEnum.One & { tag: void }
Thanks for getting back, that does make sense. How would you rewrite the code to support this scenario, though? I tried something like this:
function doAction(type: MyEnum, value: TypeMap[typeof type]): void {
switch (type) {
case MyEnum.ONE:
console.log('type:', type, ', value:', value);
break;
case MyEnum.TWO:
console.log('type:', type, ', value:', value);
break;
default:
console.log('type:', type, ', value:', value);
break;
}
}
but of course, in this case value is just going the be the union of all the types of values in TypeMap (number | string), so that doesn't work. Would we need something like T extendsExactlyAndNothingMore MyEnum?
The generic type is the correct way to do it.. the type really should be T extends MyEnum.One and not T extends MyEnum. https://github.com/Microsoft/TypeScript/pull/22348 should address that.
As a workaround, the following seems to now work with 3.3 (referring to the original):
function doAction<T extends MyEnum>(type: T & MyEnum, value: TypeMap[T]): void {
The type within a switch case gets narrowed down to something like T & MyEnum.ONE.
Tracking at #22348
Most helpful comment
As a workaround, the following seems to now work with 3.3 (referring to the original):
The type within a switch case gets narrowed down to something like
T & MyEnum.ONE.