I recently ran into a problem where TypeScript wrongly thinks a variable can be undefined. this is a simplified version:
const f = (a?: boolean, b?: boolean) => {
if (!a && !b) return;
let c: boolean;
if (a) c = false;
else c = b;
}
In the else c = b; line, a is false or undefined and b can only be true because otherwise !a && !b would have been true. but TypeScript throws an error saying:
Type 'boolean | undefined' is not assignable to type 'boolean'.
To fix the problem for now, i have added || !b to the if (a) c = false; line:
const f = (a?: boolean, b?: boolean) => {
if (!a && !b) return;
let c: boolean;
if (a || !b) c = false;
else c = b;
}
But i’m curious as to why this error happens and TypeScript can’t detect that the variable cannot be undefined.
>Solution :
Half-joking answer: because typescript doesn’t model quantum entanglement.
More seriously, typescript’s type narrowing is basically a one-way process. It starts at the top and walks through all the branches of the code, narrowing as it goes. To detect the situation you’re asking about it would need to be able to back track, or to remember more complicated associations than the type system supports
Let’s step through the code and see what typescript sees. First we have this:
if (!a && !b) return;
Before this line, a is boolean | undefined, and so is b. Typescript tries to narrow these down, but it can’t. a might still be undefined (if b is true), and vice versa. So after this line, a‘s type is still boolean | undefined, and same for b.
A bit later we get to this:
if (a) c = false;
Looking only at the types and the code on this line, what can typescript deduce? It knows that if we get into the else case, then a must be false or undefined. But it can’t deduce anything about b.
To deduce something about b you need to know about the previous checks that have happened to b. Typescript does indirectly have information about the past checks: it has b‘s narrowed type. But since the type didn’t actually narrow (it’s still boolean | undefined), that won’t help here. Typescript would either need to have the ability to backtrack and re-evaluate, or to support types that encode the correlation between multiple variables (see quantum entanglement joke)