Skip to main content

Optional chaining operator

Optional chaining (?.) is a modern operator (ES2020) that lets you safely access object properties even when part of the chain is undefined or null. Instead of a long run of guards you write a single symbol and get undefined where you used to get a TypeError.

Theory

TL;DR

  • ?. short-circuits the chain as soon as the left side is null or undefined and returns undefined.
  • Three forms: property access obj?.prop, method call obj.method?.(), index access arr?.[0].
  • The equivalent under the hood: obj == null ? undefined : obj.prop.
  • It checks only for null and undefined, not for "empty" values like 0, '' or false.
  • It pairs nicely with ?? for a default value.
  • It cannot be placed on the left-hand side of an assignment.

Quick example

javascript
const user = { profile: { name: 'Alice' } }; console.log(user.profile?.name); // "Alice" console.log(user.address?.city); // undefined (no error)

The problem without optional chaining

Suppose we have a nested object:

javascript
const user = { profile: { name: 'Alice' } };

If we try to reach a field that does not exist:

javascript
console.log(user.address.city); // TypeError: Cannot read properties of undefined

The error happens because user.address is undefined, and trying to read undefined.city breaks the code.

The solution, the ?. operator:

javascript
console.log(user.address?.city); // undefined (no error)

If the value before ?. exists, the property is returned. If it is undefined or null, the result is undefined and the program does not crash.

Forms of the syntax

1. Property access

javascript
user?.profile?.name // "Alice" user?.address?.city // undefined

2. Method access

javascript
user.sayHi?.(); // calls the method if it exists

3. Array element access

javascript
const arr = null; console.log(arr?.[0]); // undefined (no error)

An example with API data

javascript
const response = { user: { name: 'Alice', address: null } }; console.log(response.user?.address?.city); // undefined

Without ?. you would have to write long guards:

javascript
response && response.user && response.user.address && response.user.address.city

Optional chaining with nullish coalescing

These two operators are often used together:

javascript
const city = user.address?.city ?? 'Not specified'; console.log(city); // "Not specified"
  • ?. accesses the property safely.
  • ?? supplies a default value when the result is undefined or null.

Unlike ||, the ?? operator does not replace valid falsy values: 0 ?? 10 gives 0, while 0 || 10 gives 10.

What it does under the hood

javascript
obj?.prop // equivalent to: obj == null ? undefined : obj.prop

The loose comparison == null is true for both null and undefined, so one operator covers both cases. An important detail: the chain short-circuits, so in a?.b.c the rest of the expression is not evaluated at all when a is null.

Where you can use it

SituationExampleResult
Object propertyuser?.name'Alice' or undefined
Nested objectsuser?.address?.citysafe
Method calluser.method?.()called if the method exists
Array elementarr?.[0]the first element or undefined

Where you cannot use it

javascript
// not allowed on the left of an assignment user?.name = 'Alex'; // SyntaxError // not an existence check: it yields undefined, not false if (user?.missing) { /* ... */ }

Summary table

What it doesHow it works
Optional chaining (?.)Accesses a property safely without throwing
Returnsundefined when it meets null or undefined
Used foraccessing nested properties, methods and elements
Combined with?? most of the time, for default values

Common mistakes

  • Putting ?. in every link "just in case". It masks real bugs: if user always exists by contract, user?.profile only hides a data problem.
  • Confusing it with an "empty value" check. ?. reacts only to null and undefined; 0, '' and false pass through as ordinary values.
  • Combining ?? with || or && without parentheses. a ?? b || c is a SyntaxError, explicit parentheses are required.
  • Forgetting that the chain can still throw after a ?.. In user?.address.city only user is guarded; if address is undefined, you get a TypeError.
  • Calling a method as user?.sayHi() instead of user.sayHi?.(). The first form only guards against a missing user, not against a missing method.
  • Using ?. on the left of an assignment. That is a syntax error, the operator is read-only.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.