TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Type narrowing with union types create impossible case with else statement

Open spsquared opened this issue 9 months ago • 6 comments

🔎 Search Terms

else type narrowing

🕗 Version & Regression Information

  • This is the behavior in every version available on the typescript playground, and the FAQ doesn't seem to mention it
  • EDIT: it only seems to happen when there are more type unions within the type union

⏯ Playground Link

EDIT: this is a bad example https://www.typescriptlang.org/play/?ts=5.4.5#code/C4TwDgpgBAQgrgcygXigbwFBW1AhgLigHIAeZIgGixwCNCA7OAWxogCcMBfKAH3WuwFiAPnJUcUAMYNmrDpwwYA9EqgATAPYQAzvSLAoAdw1sA1gH4MkjfW0HgO4IXhJUmCUNJiBUOlABMXBgAlgBmUAAUDnYAdLgoqF5EAJT8Eiq+UBAAHsF22nj0alJSuPT0GsA+1rYaADYQMXUaCFGOMTTJ1Tba9Y3NrdHAMZJd3BB12tDuOBnB9FC9TNCSuFMFwAAW7NB5eFAARNZMYLhseTZ4YJBnBXD08w70wME2uHUHWWxsJlBhUABJKDANggYEaKQaE5naBDOI+DL0CDBLbsEq-GhZXJ2KDbNjQCAANwgCy2GkQm32TDgONYInIhWKqPxoRMKyg1JxOTyVQkNV6DSaLTasU63VqgoGIuGoyCylUNDg9k2e2MZm0GFC90kL0uQ38UWciFSM2w-yicQSxDIKTSEhw-L6QsGHS6EnGk2mPj5PSdUplbpwCk4QA

💻 Code

EDIT: still a bad example, assume test is not known

type Bug = {
    a: '<=',
    b: number
} | {
    a: '>=',
    c: number
}

// doesn't work?
const test: Bug = {
    a: '<=',
    b: 2
}
if (test.a == '<=') {
    // b exists and c cannot
    console.log(test.b)
    console.log(test.c)
} else {
    // in some cases there is a "comparison appears unintentional" error if I try to compare test.a
    // neither c or b exist here even though a must be '>=' and therefore c must exist
    console.log(test.b)
    console.log(test.c)
}

// but this works
function test2(t: Bug) {
    if (t.a == '<=') {
        console.log(t.b)
    } else {
        console.log(t.c)
    }
}

🙁 Actual behavior

else statement does not type narrow properly in some cases.

In my code it's impossible to get around this as the type narrowing DOES work properly in further if statements, which prevents me from simply checking with the same comparison again with a return statement.

image

The example given uses the value of a to determine whether to use b or c, but the narrowing doesn't allow any code in the else to use either.

🙂 Expected behavior

The type narrowing checks for the if condition inside the else block should also apply to other code in the else block.

Additional information about the issue

spsquared avatar May 15 '24 03:05 spsquared