Home > Back-end >  How can I make typescript treat a typed function as a throw-statement?
How can I make typescript treat a typed function as a throw-statement?

Time:09-10

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.

Playground

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}`);
}
  • Related