Let's consider the following code:
function f(x : number) {
if (x === 1) {
if (x === 2) {} // error
}
else {
if (x === 1) {} // OK
}
}
Here, the compiler gives me an error on x === 2
.
The reason is simple: if execution has reached this block then x
should be 1
as x === 1
passed.
And since 1
and 2
have no overlap it is impossible for x
to be both 1
and 2
.
But the compiler is totally OK with the second x === 1
inside the else
.
This should not be possible as x
has already failed check for x === 1
in the if
statement.
And since x
cannot satisfy both x === 1
and !(x === 1)
the second if
should give me the same error as for x === 2
.
How is this possible? Is this some kind of not implemented feature of advanced flow analysis? Is this a bug? Or maybe this case have some hidden logic and in the end it does have some sense?
Thanks.
CodePudding user response:
Because Typescript isn't capable of expressing a not type, such as number
but not a specific number.
When you do:
if (x === 1) { x } // x is type: 1
Then it knows x
is 1
in that block. This is fine, 1
is valid and useful type. And it's trivial to statically say that 1 === 2
can never be true.
But in the else block here:
if (x === 1) { x }
else { x } // x is type: number
Then x
is type number
, because the type system cannot express "all numbers except 1
". So the compiler cannot actually guarantee that code path cannot be taken, even though you can see that.
It's a limitation of the type system, sure. But Typescript isn't perfect. It's a type system on top of a different language, and this one of those things where you're going have to settle for good enough.