th.
a mug of tea sitting next to a pile of herbs
Photo by Kelly Sikkema on Unsplash.

Loose null checks in JavaScript

03 Jun 2024 • 3 min read

tl;dr: value == null is an easy way to capture both null and undefined in a equality check, and it's the one clear case that a loose equality check is better than a strict equality check.

By default, I always use strict equality checks when writing JavaScript. There are plenty of articles and StackOverflow answers explaining why you should use strict equality (===) instead of loose equality (==). For just about every case, I agree that strict equality checks are the way to go–except when working with null values.

Two ways to express null

One of the quirks of JavaScript is that there are two ways to express a null or "nothing" value–null and undefined. Though similar, these two values aren't exactly the same:

  • undefined indicates that there was nothing set or returned by a function. If you declare a variable without setting it to a value (e.g. let myVariable;), by default it has a value of undefined. I have observed that JavaScript mostly uses undefined in functions as the "none" value (though, in true JavaScript fashion, there are exceptions to this, like in the exec() method of the regular expression object).
  • null indicates the intentional absence of a value. For example, in a getter function, you might return null if the value is not found.

I have often seen these two used interchangably, despite them not being quite the same. My rule of thumb is to use null as much as possible, because it is a clearer (but not perfect) indication that the code returning the null was written by a human.

Handling both values with one check

Since both of these values exist in JavaScript, we need to accomodate each one in conditionals. Sometimes in the name of "always doing strict checks", I will see the following code:

if (value === undefined || value === null) {
  // ...
}

This code is totally correct! But there is a simpler, more elegant way:

if (value == null) {
  // ...
}

This works because both null and undefined are falsy, and are equivalent to each other in a loose check–you can see this for yourself if you run the following in the browser console:

console.log(null == undefined);

That logs out true! The MDN docs on null give a complete explanation of how null and undefined resolve in various types of checks.

I find that using a loose null check everywhere lets me care less about "which kind of null value is it" and simply check if it is one of the possible null values.

Practical example

This is really useful in TypeScript when mixing null with optional parameters. Imagine you have a Button function that optionally takes in an Icon. The icon prop also accepts null so that the consumer can pass in null as well:

interface ButtonProps {
  title: string;
  icon?: Icon | null;
}

In this example, the loose equality check comes in handy:

function Button({title, icon}: ButtonProps) {
  if (icon == null) {
    return <button>{title}</button>;
  }

  return (
    <button>
      {icon}
      {title}
    </button>
  );
}

Loose null checks are simpler, easy to read, are a bit more elegant than checking null and undefined separately.

Reply to this post on Twitter
© 2024 Trevor Harmon