Faced with the strange behavior of TS.
const isItLanding = false;
if (isItLanding === undefined) { // valid
return ...;
}
But here
const isItLanding = 1;
if (isItLanding === 'undefined') { // error
return ...;
}
Why doesn't TS insure against writing invalid comparisons? And how can I change this behavior?
My TS config looks like:
{
"compilerOptions": {
"strict": true,
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"importsNotUsedAsValues": "error",
"allowSyntheticDefaultImports": true,
"incremental": true,
"tsBuildInfoFile": ".next/cache/.tscache/",
"jsx": "preserve",
"sourceMap": true,
"baseUrl": ".",
"paths": {
"~/*": ["src/*"],
"test-utils": ["./src/client/test-utils"]
}
},
"exclude": ["node_modules", "cypress"]
}
CodePudding user response:
Short answer: TypeScript intentionally allows any type to be compared to "null" or "undefined"
It is allowed because boolean can be undefined
In TypeScript boolean can hold four values true
, false
, undefined
and null
, what means that by definition there might be a case where the comparison will in fact be true.
let bool: boolean = true;
bool = false;
bool = null;
bool = undefined;
//All compiles without an issue
if(bool === undefined){
console.log("You will see me!");
}
How to ensure that boolean can only be true or false?
In your TS config you can set a flag strictNullChecks
to true
, this way when type is checked both undefined
and null
will be taken into account.
Once this flag is set, the code above will return an error.
let bool: boolean = true;
bool = false;
bool = null; //Error > Type 'null' is not assignable to type 'boolean'.
bool = undefined; //Error > Type 'undefined' is not assignable to type 'boolean'.
Why after changing the flag comparison to null or undefined is still allowed?
Consider the code below:const bool: boolean = false;
if(bool === undefined){
console.log("I am undefined!");
}
if(bool === null){
console.log("I am null!");
}
console.log("It compiled?");
Why neither of these if statements return an error, even if they are always false?
The answer might be disappointing to some, but the reason is simple: It is intentionally designed that you can compare any type to "null" or "undefined". It's the way the language was constructed, that is to allow defensive programming. It might be changed in the future, if there is enough of demand, but I personally don't think there ever will be.
if(12 === undefined){
console.log("impossible isn't it?");
}
if("ab" === null){
console.log("no way it will ever be true!");
}
if(false === undefined){
console.log("never ever");
}
/*
if(12 === "ab")
^this would error as comparison to different types is allowed only with null and undefined
*/
console.log("Yet, it will indeed compile");
CodePudding user response:
I found the right rule in the linter at https://typescript-eslint.io/rules/no-unnecessary-condition. This completely solves the problem!