Jasper Schulte
Jasper Schulte

Reputation: 7361

Why does TypeScript throw an error in an if statement checking an Union Type as if it's just a Literal Type?

Take the following TypeScript code:

const a: 0 | 1 = 1

if (a === 0) {
    console.log('a is 0')
}

The if statement will generate the following error:

This condition will always return 'false' since the types '1' and '0' have no overlap.

(you can play around in in the TypeScript Playground with this example here: https://www.typescriptlang.org/play?#code/MYewdgzgLgBAhgLhgBhgHxgRhgXiwKHwEsAzGACjlxz2QEoYBvfGVmUSEAGwFMA6LiADm5AORUiEFKLr4AvkA)

My question is why does this throw an error? If you hover over the type of a it is correctly typed as const a: 0 | 1. If the compiler is so sure a's type is always 1, why doesn't it type it as const a: 1?

NB: If you change the code to...

const a = 1 as 0 | 1

if (a === 0) {
    console.log('a is 0')
}

...the error will go away. But it seems silly to revert to casting to fix this.

Upvotes: 1

Views: 783

Answers (1)

Etheryte
Etheryte

Reputation: 25318

The "problem" here is that Typescript is smart enough to understand that const can't be reassigned. This means that

const a: 0 | 1 = 1;

is the same for Typescript as doing

const a: 1 = 1;

Even though the type indicates there is a range of possible values, const assignment limits the type to the only possible value.
You can see this in action when you hover a in the conditional in the playground snippet you linked to: the type of a in the if statement is 1.

When you cast the type after the fact, you're manually overriding this constraint.

You can see the same operation in action when your variable declaration is let but no assignment is made:

let a: 0 | 1 = 1;

// Same error as before, type of `a` is `1`
if (a === 0) {
    console.log('a is 0');
}

If there's an assignment to the variable though, the type can't be constrained (because that would be the equivalent of the halting problem), and you'll have no error.

let a: 0 | 1 = 1;

if (some external condition) {
    a = 0;
}

// No error, type of `a` is `0 | 1`
if (a === 0) {
    console.log('a is 0')
}

Upvotes: 1

Related Questions