I am struggling with a typescript inconvenience - I have a custom function that always throws an error, and I am using it to throw errors in case certain variables are null. If I don't use the function, but rather just throw an error, typescript understands that the variable cannot be null after that statement, but if I use a function typed with the 'never' return type, it does not.
See this example on TS Playground that perfectly illustrates the problem.
Is there any way to get around this?
Currently, I have to do one of the following:
- Change my types to allow null (that would be very bad for various reasons)
- Add a reduntant mock throw statement similar to the one in the code example (annoying but works)
I have tried using the recommended function signature with the return type of never, but typescript still treats it differently from an explicit throw statement. I expected that if a function never returns, typescript understands that the rest of the code won't execute.
CodePudding user response:
You may be looking for an assertion function.
function customThrow(str: string | null, message: string): asserts str is string {
if (str === null){
throw new Error(`custom-error-${message}`);
}
}
const cat: string | null = Math.random() > 0.5 ? 'cat' : null;
customThrow(cat, "cat-missing")
const uppercaseCat = cat.toUpperCase();
The function asserts that whatever is passed into it must be a string
, otherwise the function throws an Error
. You might also change the naming of the function to something like assertStringNotNull
.
CodePudding user response:
If anyone is curious, the problem stemmed from this issue
And the solution is explicitly typing the function every time we want it to participate in the control flow.
A working playground can be found here
The example from my first playground
const customThrow = (message: string): never => {
throw new Error(`custom-error-${message}`);
}
Needs to be explicitly typed like this
const customThrow: (message: string) => never = (message) => {
throw new Error(`custom-error-${message}`);
}