JavaScriptOptional ChainingFrontendTypeScript

JavaScript Optional Chaining: When to Use `?.`

Learn how optional chaining works for property access, array indexes, and function calls, and when to pair it with nullish coalescing instead of hiding real data errors.

·Updated ·7 min read·Counting...
JavaScript Optional Chaining: When to Use `?.`

Optional chaining does not mean "never throw errors." It means "if this specific part of the chain is null or undefined, stop and return undefined instead of trying to keep accessing properties." It is useful for API responses, optional callbacks, optional configuration, and UI data that may not be loaded yet.

It becomes harmful when it is used everywhere and hides data that should be required.

Basic forms

object?.property
object?.[index]
object?.method?.()

The rule is:

  • If the value on the left is null or undefined, the expression returns undefined.
  • Otherwise, JavaScript continues the normal property access, index access, or call.

Nested property access

const user = {
  profile: {
    city: "Hangzhou",
  },
}

user?.profile?.city // "Hangzhou"
user?.profile?.zipCode // undefined

This replaces older defensive patterns:

user && user.profile && user.profile.city

Optional chaining is clearer because it checks nullish values, not every falsy value.

Optional function calls

onSuccess?.(result)

This is common for React props, plugin callbacks, and optional hooks. You do not need:

if (onSuccess) {
  onSuccess(result)
}

However, if onSuccess exists but is not a function, optional chaining is not a type system. You can still get an error. Validate the shape of untrusted data at the boundary.

Arrays and index access

items?.[0]
response?.data?.[0]?.id

This helps when the array itself may be missing. It is not needed just because an index might be out of range; normal JavaScript array access already returns undefined for missing indexes.

Use ?? more often than ||

This is a common bug:

const count = user?.count || 0

If count is 0, the expression still falls back to 0. That example looks harmless, but the same pattern breaks with empty strings and false booleans.

Prefer nullish coalescing when you only want to handle null and undefined:

const count = user?.count ?? 0

Difference:

  • || falls back for any falsy value.
  • ?? falls back only for null or undefined.

Optional chaining and nullish coalescing often belong together.

When not to use optional chaining

Do not make required objects optional:

config?.apiBaseUrl

If config must exist, this hides an initialization error. You may only discover the problem later when undefined reaches another part of the app.

Do not turn every level into uncertainty:

app?.store?.user?.profile?.settings?.theme

Sometimes that code is correct for external data. But inside your own app, it often means the data model has not been narrowed at the boundary.

Also remember that optional chaining does not protect an undeclared top-level variable:

foo?.bar

If foo was never declared, JavaScript still throws ReferenceError.

A realistic UI example

const avatarUrl =
  response?.data?.user?.avatar?.url ?? "/images/default-avatar.png"

Here ?. safely crosses uncertain API levels, and ?? supplies the default only when the result is nullish. That is a clean boundary: uncertain data is handled at the point where it enters display logic.

Subscribe to FreeMac

Weekly picks: free Mac software reviews, trusted source updates, alternatives, and low-friction guides.