I am wondering if there is a technical reason that TypeScript declines to warn on the if statement below when compilerOptions are "strict": true
and "strictNullChecks": true
.
Or, if this is something I am doing wrong in the construction of the type, where this would be possible to enforce.
let a2: Array<Uint32Array> = [];
if (a2 === null) { // this is not an error or warning, even though a2 can never be null
console.log('this will never happen');
}
a2 = null; // this (correctly) gives a TS error, since a2 can never be null!
in fact even adding a non-null assertion doesn't give an error or warning!
if (a2! === null) {
// ... no error
The canonical answer to this question can be found at microsoft/TypeScript#11920, a longstanding open feature request for such comparisons to issue type errors. While TypeScript will indeed complain if you compare a2
to most random values (e.g., a2 === 3
or a2 === {a: 0}
will both produce errors), null
and undefined
are explicitly exempt from this:
We intentionally allow this for the sake of defensive programming (i.e. defending against missing inputs from non-TS code). If there's enough demand we could add a flag or something.
Paraphrasing: their rationale is that even though TypeScript is convinced that a2
can never be null
or undefined
, it still allows checks against them so that people who are worried about null
or undefined
unexpectedly showing up at runtime can easily harden their code against it. Presumably null
and undefined
are considered more likely at runtime than 3
or {a: 0}
.
So that's their reasoning. You might not agree with it, but that's what it is. The feature request at microsoft/TypeScript#11920 asks for this to be changed to the more strict check you're asking about. That request has been open for a long time, is marked as Awaiting More Feedback and only has a few dozen upvotes. Right now it seems unlikely that it will be implemented. Anyone who wants to increase that likelihood might want to go to that issue, give it a 👍, and possibly leave a comment describing a compelling use case (if it is not already mentioned by someone else). But pragmatically speaking I wouldn't wait for this.
If you really need a warning for such comparisons today, you might consider using a linter like typescript-esLint and enabling an appropriate rule like @typescript-eslint/no-unnecessary-condition
, where
any expression that always evaluates to truthy or always evaluates to falsy, as determined by the type of the expression, is considered unnecessary and will be flagged by this rule.
That produces the following warning:
let a2: Array<Uint32Array> = [];
if (a2 === null) { // error!
//~~~~~~~~~~~
//Unnecessary conditional, the types have no overlap
console.log('this will never happen');
}
as desired.