Nullish Coalescing Operator '??'

Can you recognize yourself in one of the following snippets you? If yes, hang tight, because we will look at a better way to provide fallbacks right after.

1. Override variable, if it's undefined or null

let val = getValueFromApiRequest();
if (val === null || val === undefined) {
val = "fallback value";
}
doSomethingWith(val);

This can be slightly shortened:

let val = getValueFromApiRequest();
doSomethingWith(val === null || val === undefined ? "fallback value" : val);
// or switching the order of the logic (but basically the same thing):
doSomethingWith(val !== null && val !== undefined ? val : "fallback value");

The Nullish Coalescing Operator cannot be used on a non-declared root object, but can be used with an undefined root object. Hence we are declaring let val before in some way:

let val = getValueFromApiRequest();

2. Using lodash.defaultTo (or lodash.get for object properties)

Note, that _.defaultTo will return the fallback if the value is undefined, null, or NaN. On the other hand, _.get will only return the fallback, if the property is undefined. If it's null, null will be returned.

import defaultTo from "lodash.defaultTo";
import get from "lodash.defaultTo";
// or alternatively:
// import defaultTo from 'lodash/defaultTo';
// import get from 'lodash/get';
let val = getValueFromApiRequest();
doSomethingWith(defaultTo(val, "fallback value"));
// or for object properties:
doSomethingWith(get(val, "some.property", "fallback value"));

3. Check only for "truthy" (or "falsy")

Often enough it's sufficient to just check very shallowly for a falsy value. That means, that the fallback will be used if the value is either false, 0, -0, 0n, "", null, undefined, or NaN (the other way around, a truthy value is none of those).

let val = getValueFromApiRequest();
if (!val) {
val = "fallback value";
}
doSomethingWith(val);

There is slightly shorter variations of this, too:

let val = getValueFromApiRequest();
doSomethingWith(val || "fallback value");
// or
doSomethingWith(val ? val : "fallback value");
// or
doSomethingWith(!val ? "fallback value" : val);

This is usually safe to use and probably the most common fallback check of all. It will only lead to issues, if the passed values are actually valid arguments in the used function.

For example, the following example would cause unwanted behavior, which would be really hard to find (because there is no syntactical error):

const add = (a, b) => {
return a + b;
};
let val1 = 7,
val2 = 0;
const doSomething = () => {
// 0 is falsy, and so the program will execute
// the code in the else-clause
if (val1 && val2) {
return add(val1, val2);
} else {
return add(1, 2);
}
};
doSomething();
// => 3

The better way to provide fallback values in JavaScript

In December 2019, the TC39 proposal for the Nullish Coalescing Operator (??) has reached stage 4 (which means finished and ready to be included into EcmaScript). Node.js >= 14 supports it as well as ~87% of today's used browsers.

If you have to support older browsers or are not yet on newer Node.js versions, you can use @babel/plugin-proposal-nullish-coalescing-operator to transpile your code (every occurrence of it will bloat the bundle size a little, but that's practically irrelevant in most cases).

Anyway, we can close the loop here, as the Nullish Coalescing Operator simply is an actual shortcut for the first and most explicit fallback check which we learned earlier: Checking for undefined or null.

let val = getValueFromApiRequest();
// Now, instead of
doSomethingWith(val !== null && val !== undefined ? val : "fallback value");
// we can write:
doSomethingWith(val ?? "fallback value");

That's pretty much the conveniently simple gist. If you like, you can read up on caveats like precedence here.

Maxim Zubarev Avatar

A personal publication by Maxim Zubarev.
I use software as a leverage for business.