'Why the typescript narrowing seems doesn't work with default value?

why in TestErr function does the variable testvar inside the if-else block give the type string | number?

Seems it works only without default value. But the variant seems correct in both cases.

typescriptlang demo

type A = {
  variant?: "1" | "2";
  testvar: number;
}

type B = {
  variant: "99"
  testvar: string;
}

type TestProps = 
| A
| B

function TestErr({variant = "1", testvar}: TestProps) {
  if (variant === "99") {
    if (variant === "1") {}  // error as expected 
    testvar; // testvar: string | number
  } else {
    if(variant === "99") {} // error as expected 
    testvar; // testvar: string | number
  }
  testvar; // testvar: string | number
}

function TestOk({variant, testvar}: TestProps) {
  if (variant === "99") {
    if (variant === "1") {}  // error as expected 
    testvar; // testvar: string
  } else {
    if(variant === "99") {} // error as expected 
    testvar; // testvar: string
  }
  testvar; // testvar: string | number
}


Solution 1:[1]

You are assign the default value of 1 to variant in TestErr, in this way TS can not discriminate the types.

You can see that in TestOk, variant is of type "1" | "2" | "99" | undefined" that is correct since variant in type A could be undefined.

But, because you assign a default value to variant in TesErr, now the type become "1" | "2" | "99" which is not what we are expecting from TestProps.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1