Here's a playground link.
interface Animals {
cat: {}
dog: {}
}
function brokenSwitch<T extends keyof Animals>(animal: T) {
switch (animal) {
case "cat":
break
case "dog":
break
default:
// the line below has a TS error.
// Type "cat" | "dog" is not assignable to type "never".
const remainingAnimal: never = animal
}
}
In the above code, I would expect the type of animal
in the default
case to be never
, but it is not.
In my real use case, I need the function to accept a generic similar to this function. How can I get TS to narrow down the type of animal
successfully as we go through the switch block?
I notice that from TS 4.3.5 and on, the type is narrowed the way I'd expect (the error disappears), but I can't change the TS version of my project.
Before TypeScript 4.3, the way to deal with your problem would be to widen
animal
from the generic typeT
to the specific typekeyof Animals
to which it is constrained. This is most easily done by assigninganimal
to a new variable which is annotated as the specific type. Such an assignment is seen as safe by the compiler. Afterward, you use the new variable which will then be narrowed as expected:So that works, and the end of the answer to the question as asked.
Obligatory disclaimer:
Note that the "correct" answer is to upgrade to the latest TypeScript release, both to take advantage of the support for contextual narrowing of generic values added in TypeScript 4.3 and to avoid the rapidly increasing amount of technical debt that comes from a depending on a static version of a language under such active development. Bug fixes are rarely backported to previous versions (see microsoft/TypeScript#38237), so it's not really possible to subscribe to a "long-term support" version of TypeScript 3.8, which eventually becomes bug-free and is accompanied by a large amount of accurate documentation and other development resources.
You (the OP of this question) may have valid reasons for sticking with a static version of the language, but you (other people who read this answer in the future) should strongly consider upgrading if at all possible.
Playground link to code