Home > Net >  Why do string type appears in the else branch of the code when it was dealt in the if branch?
Why do string type appears in the else branch of the code when it was dealt in the if branch?

Time:12-28

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
  }
}
  • Related