Author
Chiamaka Ikeanyi.
Follow Chiamaka Ikeanyi on Twitter

Nullish Coalescing and Optional Chaining in JavaScript

When working with data, situations arise where you aren’t sure that the property you need exists. To build fault-tolerant applications despite issues like this, default values are provided to make apps fail gracefully. Before now, the logical OR (||) operator is used to achieve this. It is a syntax for selecting the second defined value or variable (default value) if the first value or variable is falsy (false, 0, ' ', null or undefined).

The logical OR (||) operator

The tenary condition a ? a : b is shortened to a || b. This concept is known as short-circuiting.

The result of actualValue || defaultValue is: actualValue if actualValue is falsy, otherwise, it is defaultValue.
console.info(null || 'default');       //'default'
console.info(undefined || 'default'); //'default'
console.info(false || 'default');    //'default'
console.info(' ' || 'default');    //'default'
console.info(0 || 'default');     //'default'

Note that the default value is also used when the actual value is false, 0 or ' '. This is due to JavaScript evaluating these values as falsy. The operand on the left hand side was coerced to a boolean for the evaluation and any falsy value (false, 0, ' ', null or undefined) is not returned. This leads to unexpected results if these values are considered valid.

To get a better grasp, let's consider the function:

function getUser(user) {
  return user.name || 'guestUser';
}

function isUserValid(user) {
  return user.isValid ?? true;
}

const users = [
  {name: 'Ethel', age: 25},
  {name: '', age: 22},
  {age: 18, isValid: false}
];

users.map(user => getUser(user));
// Expected output: ["Ethel", "guestUser", "guestUser"];

users.map(user => isUserValid(user));
// Expected output: [true, true, true];

If the expected value for the second object in the array above is ' ', the logical OR (||) operator nullifies it. A recent operator (??) has been added to JavaScript to address unexpected behaviours like this when using || operator.

The nullish coalescing (??) operator

As opposed to the logical OR (||) operator, the nullish coalescing (??) operator provides a syntax for selecting the second operand only when the first operand evaluates to either null or undefined (but no other falsy values). It is a replacement to the || operator.

The nullish coalescing operator (??) is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined, and otherwise returns its left-hand side operand.

The tenary condition (a !== null && a !== undefined) ? a : b is shortened to a ?? b.

The result of actualValue ?? defaultValue is: actualValue if actualValue is not null or undefined, otherwise, it is defaultValue.
console.info(null ?? 'default');      // 'default'
console.info(undefined ?? 'default'); // 'default'
console.info(false ?? 'default');   // false
console.info(' ' ?? 'default');    // ' '
console.info(0 ?? 'default');     // 0

Take a look at the last three operations, therein lies the difference between || and ??. Actual values are returned for the two falsy values.

Rewriting the same function,

function getUser(user) {
  return user.name ?? 'guestUser';
}

function isUserValid(user) {
  return user.isValid || true;
}

const users = [
  {name: 'Ethel', age: 25},
  {name: '', age: 22},
  {age: 18, isValid: false}
];

users && users.length > 0 &&
  users.map(user => getUser(user));
// Expected output: ["Ethel", "", "guestUser"];

users && users.length > 0 &&
  users.map(user => isUserValid(user));
// Expected output: [true, true, false];

Optional Chaining

The nullish coalescing operator is related to the optional chaining operator (?.) and can work alongside each other. Both treat null and undefined the same way which is useful when accessing a property of an object which may be null or undefined.

Given the object,

const user = {
  name: 'Eve',
  state: {
    name: 'Lagos',
    city: {
      name: 'Gbagada',
      code: 257
    }
  }
};

To access a property on this object that its availability is uncertain, we usually use the syntax below:

if(user.state !== undefined &&
  user.state.city !== undefined) {
    const stateCode = user.state.city.code;
}

This ensures that the program does not throw an error message such as:

TypeError: Cannot read property 'code' of undefined

With the newly introduced optional chaining operator (?.), you can check for data availability using a more concise approach.

console.info(user.state?.city?.code);

Given the array,

const users = [
  {
    name: 'Nora',
    state: {
      city: {
        name: 'Onitsha',
        code: '257',
      },
    },
  },
  {
    name: 'Terrence'
  },
  {
    name: 'Nick',
    state: {

    },
  },
];

const cityCode = users?.length > 0 &&
  users.map(user => user.state?.city?.code ?? 0);
// Expected output: ["257", 0, 0];
Do not combine both the AND (&&) and OR operators (||) directly with ??. A SyntaxError will be thrown in such scenario.

Note that when ?? is used together with || or && operator in an expression, always enclose the expression within parentheses due to its low value on the precedence table.

Given the object,

let user = {
  name: 'Eve',
  state: {
    name:  null
  }
};

const stateValueWithError = user.state &&
  user.state.name ?? 'Accra';
  // Uncaught SyntaxError: Unexpected token '??'

const stateValueWithoutError = (user.state &&
  user.state.name) ?? 'Lagos';

console.info(stateValueWithError);
// Uncaught ReferenceError: stateValueWithError is not defined

console.info(stateValueWithoutError); // "Lagos"

Conclusion

The main difference between the logical OR (||) and the nullish coalescing operator (??) is that || returns the first truthy value while ?? returns the first defined value. This becomes important when other falsy values are considered as valid values.

Though this feature is appealing to use, minimize its usage at this stage due to the cross-browser stability.

Article Tag  JavaScript

Share this article:

Subscribe to the Newsletter

More Articles


Author
Chiamaka Ikeanyi.

Chiamaka Ikeanyi

I create quality learning resources. If my articles have helped or inspired you in your development journey, please consider supporting me.

patreon logoBecome a Patron