Reputation: 11803
I am writing some documentation about TypeScript and I'm talking about the possible usefulness of the never
keyword, one being exhaustive checking, as described here:
I have some code like this:
type PossibleStrings = 'foo' | 'bar' | 'chaz';
function fail() : never {
throw new Error("This endpoint should never be reached");
}
function usesString(value: PossibleStrings) : number {
if (value === 'foo') {
return 1
};
if (value === 'bar') {
return 2
};
return fail();
}
Now I would expect that this would be giving an error, as you shouldn't be able to return the never
type from this function.
And actually if we just strip this down, it seems like the function is a-ok with returning a never type:
type PossibleStrings = 'foo' | 'bar' | 'chaz';
function fail() : never {
throw new Error("This endpoint should never be reached");
}
function usesString(value: PossibleStrings) : number {
return fail();
}
Seems... broken. What's going on here?
Edit: Answer is right in the documentation:
The never type is a subtype of, and assignable to, every type; however, no type is a subtype of, or assignable to, never (except never itself). Even any isn’t assignable to never.
Is there a way to change that behaviour, or otherwise get this code to behave how I want? ie. I want the return fail()
to only be valid if all other branches are exhausted.
Upvotes: 1
Views: 103
Reputation: 11803
The solution is to rather than relying on the return type of the fail function to cause compile time errors, you use the parameters of the fail function.
type PossibleStrings = 'foo' | 'bar' | 'chaz';
function fail(value: never) : never {
throw new Error("This endpoint should never be reached");
}
function usesString(value: PossibleStrings) : number {
if (value === 'foo') {
return 1
}
if (value === 'bar') {
return 2
}
return fail(value); //Argument of type 'string' is not assignable to parameter of type 'never'.(2345)
}
When the possible values are exhaustively checked, this no longer causes a compile time error.
Upvotes: 2