I was learning about equality narrowing in typescript and the official handbook presented this function as example (see this function in playground):
function example(x: string | number, y: string | boolean) {
if (x === y) {
// We can now call any 'string' method on 'x' or 'y'.
// As x and y can only be equal if they had type string
x.toUpperCase();
y.toLowerCase();
} else {
console.log(x); // x : string | number
console.log(y); // y : string | boolean
}
}
We can see that in the if
branch, both x
and y
have type narrowed down to string
. That's why we can only call string methods. It should mean that the string type is fully dealt in the if
branch and it should not appear in the else
branch. On the contrary, if we check the type of both x
and y
, they still have string
as the possible type in the else
branch. Ideally, string
shouldn't appear as a type
in the else
branch. Am I missing something or Typescript's type system is not capable enough to perform this level of narrowing at this time? Please help me to understand, Thank you!
CodePudding user response:
Ideally, string shouldn't appear as a type in the else branch
Sure they could - if they're both strings, but if the strings aren't ===
.
function example(x, y) {
if (x === y) {
// branch does not get entered into
} else {
console.log(typeof x); // string
console.log(typeof y); // string
}
}
example('foo', 'bar');
The narrowing you're expecting would occur if you used typeof
checks instead, with ||
(though that wouldn't guarantee that both values would be strings in the first branch).
function example(x: string | number, y: string | boolean) {
if (typeof x === 'string' || typeof y === 'string') {
} else {
console.log(x);
// ^? number
console.log(y);
// ^? boolean
}
}