typescript

Why doesn't typescript warn of null checks for non-nullable types?


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

Solution

  • 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.

    TypeScript-ESLint playground link to code