Typescript – Nullish Coalescing vs Logical OR

tech

This is a TypeScript concept I've struggled with for a while. It looks simple in theory, and I've used it interchangeably many times. However, I wanted to understand it perfectly once and for all. Here are my learnings:


The Why

Firstly, both of these concepts were introduced to handle inconsistent data types in TypeScript. Data coming from different sources are not always complete. Some data values could be missing. These are generally represented as undefined or null in computer terms. But these are not the only representation of missing data. Here's more:

  • 0
  • -0
  • false
  • ""
  • NaN

Hence, there's a need to provide fallback values in cases we encounter missing values, to prevent TypeScript from complaining. These two operators (|| and ??) have been introduced to address this challenge.

Logical OR or Double Pipe Operator — ||

// const name: string = await getName() — TypeScript complains here if the `getName` call can potentially return any of the above-defined missing values.

const name: string = await getName() || ""; // this provides a fallback value if `getName` returns a missing value. So the `name: string` type is maintained.

This is the purpose of the double pipe operator: <value> || <fallback value>. It essentially denotes: "If the <value> is missing, I'll default to the <fallback value>."

However, the difference between || and ?? arise when we consider the different types of missing values. || skips over all of the missing values we discussed above.

Nullish Coalescing Operator

?? can be thought of as a 'strict' version of the double pipe operator. It only skips over null and undefined missing values. For all the other missing values, it considers them, and does not default to the fallback value.

Example

Let's see the difference in action:

let name = "";
let fallbackName = "Arvind";

console.log(name || fallbackName); // "Arvind" - which is wrong!
console.log(name ?? fallbackName); // "" - correct!

let res = false;
let fallbackRes = true;

console.log(res || fallbackRes); // true - which is wrong!
console.log(res ?? fallbackRes); // false - correct!

let output = 0;
let fallbackOutput = 50;

console.log(output || fallbackOutput); // 50 - which is wrong!
console.log(output ?? fallbackOutput); // 0 - correct!

A good rule of thumb to remember is, use the nullish coalescing operator when dealing with possible 'falsy' values as your data, and use the double pipe operator otherwise.