← All concepts
Data Structures, Operators & Strings

Optional Chaining and Nullish Coalescing

?. stops a property lookup safely at the first null or undefined instead of throwing; ?? picks a default only for null or undefined.

Definition

Optional chaining, `?.`, checks whether the value to its left is `null` or `undefined` before continuing the lookup. If it is, the whole expression short-circuits to `undefined` immediately, no error is thrown, and nothing further to the right is evaluated. If it is not, the chain continues as a normal property access or method call. This makes it safe to read a deeply nested path like `user?.address?.city` even when `address` might not exist, instead of writing a chain of manual `&&` checks or a try/catch. Nullish coalescing, `??`, returns its right-hand side only when the left-hand side is `null` or `undefined`, and returns the left-hand side unchanged for any other value, including falsy ones like `0`, `""`, `false`, and `NaN`. This is the key difference from `||`, which falls through to its right-hand side for any falsy value. `0 ?? 5` is `0`, but `0 || 5` is `5`. The two operators are often combined: `user?.settings?.volume ?? 100` safely reads a possibly-missing setting and only substitutes a default when it is genuinely absent.

Examples

const user = { address: null };
user.address.city;   // TypeError: Cannot read properties of null
user?.address?.city;  // undefined, no error

Optional chaining stops the lookup the moment it hits null, returning undefined instead of throwing.

0 ?? 5;   // 0 (0 is not null/undefined)
0 || 5;   // 5 (0 is falsy)
"" ?? "x"; // "" 
null ?? "x"; // "x"

?? only falls back for null or undefined; || falls back for any falsy value, which is why 0 and "" behave differently between the two.

const settings = { volume: 0 };
const volume = settings?.volume ?? 100;
// 0, not 100

Even though 0 is falsy, ?? treats it as a present value because it is not null or undefined, so the real setting wins over the default.

Common mistakes

  • Using `||` to apply a default and accidentally overriding a legitimate `0` or empty string, when `??` was the safer choice.
  • Assuming `?.` prevents every error in a chain, when a typo further down the chain, like calling a method that does not exist, can still throw.
  • Forgetting that `?.` short-circuits the whole expression to `undefined`, so code expecting a specific error to be thrown will not see one.

Key takeaways

  • `?.` stops safely at the first null or undefined and returns `undefined` instead of throwing.
  • `??` only falls back for null or undefined, unlike `||` which falls back for any falsy value.
  • `0 ?? 5` is `0`, but `0 || 5` is `5`, because `0` is falsy but not nullish.
Check your understanding

`const volume = 0; const result = volume ?? 100;` What is `result`?

Where you see this

  • Safely reading a nested API field that might be missing, like response?.data?.user?.email.
  • Calling an optional callback only if it was provided: onSave?.().
  • Applying a default for a config value that may legitimately be 0 or an empty string, without accidentally overwriting it.
  • Replacing long defensive chains of if (a && a.b && a.b.c) checks with a single optional chain.

Practice this

Further reading

Previous
Spread and Rest
Next
Maps and Sets