Take a look at following code:
export class Smth {
private flag: boolean;
public update() {
this.flag = true;
this.inner();
if (this.flag === false) { // Operator '===' cannot be applied to types 'true' and 'false'.
console.log(123);
}
}
private inner() {
this.flag = false;
}
}
I can't understand what's wrong with the line
if (this.flag === false)
Typescript says
Operator '===' cannot be applied to types 'true' and 'false'.
But actually there are boolean
and false
.
I'm using typescript 2.6.2 but online playground shows the same result with 2.7.
It's not a dublicate of Operator '==' cannot be applied to types x and y in Typescript 2 as that question is about comparing constants. But in my code it's a chagable class field and there is a function that changes the value. Moreover, it is called.
this.flag = true;
this.inner(); // exectues this.flag = false;
if (this.flag === false) { // ... types 'true' and 'false'. - WHY?
TypeScript is kinda smart, in that it has a static analysis on your method, and it sees that you never assign anything other than false
, at lease in this closure or context - which brings the type definition to assume your variable's type is false
and not boolean
. It does not look for changes in inner called methods.
Think of the definition as if it were declared globally like this:
export type boolean = true | false
while false
is only false
, without the true
there.
There are several solutions:
Assign the type from the get-go in the class declaration, like so:
class MyClass {
private flag: boolean = true
...
}
Just don't test for direct equality, use the boolean on its own:
if (!this.flag) // instead of this.flag === false
The problem you have is part of a broader discussion about the drawbacks of flow analysis. You can read the general problem here and a very similar problem to yours here. But the gist of it is:
The primary question is: When a function is invoked, what should we assume its side effects are? One option is to be pessimistic and reset all narrowings, assuming that any function might mutate any object it could possibly get its hands on. Another option is to be optimistic and assume the function doesn't modify any state. Both of these seem to be bad. This problem spans both locals (which might be subject to some "closed over or not" analysis) and object fields.
The simple way to work around this is to cast the constant to the general type. You should do this where necessary, one could argue the error has some value, as it warns you about possibly unreachable code and can be easily disabled where erroneous:
export class Smth {
private flag: boolean;
public update() {
this.flag = true as boolean;
this.inner();
if (this.flag === false) {
console.log(123);
}
}
private inner() {
this.flag = false;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With