Question

JavaScript Optional Chaining with Arrays and Functions

typescriptjavascriptarraysfunctionoptional-chaining

Question

How can optional chaining be used with an array result and with a function property in JavaScript?

For example, how can I safely get the first matching item from an array?

myArray.filter(x => x.testKey === myTestKey)?[0]

I also want to conditionally call a function stored in an object property:

const x = { a: () => {}, b: null };
console.log(x?b());

Both attempts produce errors. What is the correct optional chaining syntax for array indexing and function calls?

Short Answer

Optional chaining uses ?. as one operator. In JavaScript, use ?.[index] to safely access an array element and ?.() to call a function only when the value is not null or undefined. You will also learn where to place optional chaining in a property, method, and array-access expression.

Concept

Optional chaining lets an expression stop safely when a value is null or undefined.

Instead of throwing an error such as:

const user = null;
console.log(user.name); // TypeError

use ?.:

const user = null;
console.log(user?.name); // undefined

The operator has forms for several kinds of access:

  • Object property: object?.property
  • Computed property or array index: value?.[key] or value?.[0]
  • Function call: fn?.()

The important detail is that ?. must stay together. Writing ?[0] is not optional chaining: ? begins the conditional (ternary) operator in JavaScript.

Optional chaining only handles null and undefined. It does not hide every possible error. For example, value?.() still throws if value exists but is not callable, such as a number or string.

Mental Model

Think of optional chaining as checking whether a path is still open before taking the next step.

  • user?.address means: “If there is a user, look up address; otherwise stop and return undefined.”
  • items?.[0] means: “If there is an items collection, open drawer number 0; otherwise stop.”
  • callback?.() means: “If there is a callback function, press its button; otherwise do nothing and return undefined.”

Each ?. protects the specific step immediately after it. Place it at the point where a value might be missing.

Take Quiz

Syntax and Examples

Use these three optional chaining forms:

// Optional object property
object?.property;

// Optional computed property or array index
array?.[0];
object?.[dynamicKey];

// Optional function call
callback?.();

Optional array indexing

const colors = ["red", "blue"];
const noColors = null;

console.log(colors?.[0]);   // "red"
console.log(noColors?.[0]); // undefined

The ?.[0] form checks whether colors exists before reading index 0.

Getting the first filtered result

filter() always returns an array when it is successfully called. Therefore, if myArray is definitely an array, no optional chaining is needed after filter():

const firstMatch = myArray.filter(item => item.testKey === myTestKey)[0];

If myArray itself might be null or undefined, protect the method call:

const firstMatch = myArray?.filter(item => item.testKey === myTestKey)?.[0];

The second ?. is useful because the expression might have stopped and returned undefined before indexing.

For finding one matching item, find() is usually clearer and avoids building a new filtered array:

const firstMatch = myArray?.find(item => item.testKey === myTestKey);

Optional function calls

const x = {
  a: () => "ran a",
  b: null
};

console.log(x.a?.()); // "ran a"
console.log(x.b?.()); // undefined

If the object may also be absent, protect both the object access and the call:

const maybeX = null;
console.log(maybeX?.a?.()); // undefined

Step by Step Execution

Consider this code:

const orders = [
  { id: 1, status: "pending" },
  { id: 2, status: "paid" }
];

const paidOrder = orders?.find(order => order.status === "paid");
console.log(paidOrder?.id);

Execution proceeds as follows:

  1. orders?.find(...) checks whether orders is null or undefined.
  2. orders is an array, so JavaScript calls find().
  3. find() tests the first order. Its status is "pending", so it continues.
  4. It tests the second order. Its status is "paid", so find() returns { id: 2, status: "paid" }.
  5. paidOrder?.id checks whether a matching order was returned.
  6. It was, so the result is 2.

If no order had status "paid", find() would return undefined. Then paidOrder?.id would safely return undefined rather than throw an error.

For a callback example:

function saveRecord(record, onSaved) {
  console.log(`Saving ${record.id}`);
  onSaved?.(record);
}

saveRecord({ id: 7 }, null);
  1. saveRecord logs the record ID.
  2. onSaved is null.
  3. onSaved?.(record) does not call anything and evaluates to undefined.
  4. No error is thrown.

Real World Use Cases

Optional chaining is useful when data or behavior is genuinely optional.

  • API responses: An API may omit a nested field.

    const city = response?.data?.customer?.address?.city;
    
  • First item in optional data: A page may render before an API array arrives.

    const avatarUrl = users?.[0]?.profile?.avatarUrl;
    
  • Optional event handlers: A reusable component may accept a callback only in some situations.

    onClose?.();
    
  • Optional integrations: An application may call a logger, analytics hook, or plugin only when configured.

    analytics?.track?.("checkout_completed");
    
  • Searching fetched records: A matching record may not exist.

    const email = customers?.find(c => c.id === customerId)?.email;
    
Take Quiz

Real Codebase Usage

In real projects, optional chaining is commonly combined with clear defaults, validation, and early returns.

Optional callback pattern

Library and UI code often receives callbacks that callers may omit:

function downloadFile(url, onComplete, onError) {
  try {
    // Download work would happen here.
    onComplete?.(url);
  } catch (error) {
    onError?.(error);
  }
}

Guard clauses for required values

Do not use optional chaining when a value is required for the function to work. Validate it instead:

function sendWelcomeEmail(user) {
  if (!user?.email) {
    throw new Error("A user email is required.");
  }

  return `Email sent to ${user.email}`;
}

Default values with ??

Optional chaining returns undefined when it short-circuits. Use nullish coalescing to provide a fallback:

const firstTag = post?.tags?.[0] ?? "untagged";

?? only falls back for null and undefined, so valid values like 0, false, and "" are preserved.

Prefer find() for one result

When only one matching item is needed, codebases commonly use find() rather than filter()[0]:

const activeUser = users?.find(user => user.active);

It communicates the intent directly and stops searching after the first match.

Common Mistakes

Writing ?[0] instead of ?.[0]

This is invalid optional chaining syntax:

const first = items?[0];

Use:

const first = items?.[0];

? by itself belongs to a ternary expression such as condition ? yes : no.

Calling an object as though it were a function

This is not property access:

const x = { b: null };
x?b();

To access property b and call it only if it exists, use a dot and ?.():

x.b?.();

If x can also be missing:

x?.b?.();

Protecting the wrong part of the expression

This can still fail when users is null:

const name = users[0]?.name;

The array access happens before ?.name. Protect the array access itself:

const name = users?.[0]?.name;

Assuming optional calls validate function types

Optional calls skip only null and undefined:

const callback = 42;
callback?.(); // TypeError: callback is not a function

If a value may have an unknown type, check it explicitly:

if (typeof callback === "function") {
  callback();
}

Using filter()[0] when find() expresses the intent

This works, but creates an array of all matches:

const user = users.filter(user => user.id === id)[0];

When only the first match matters, prefer:

const user = users.find(user => user.id === id);

Breaking a chain with parentheses

Optional chaining does not automatically protect operations after a grouped result:

const user = null;
const city = (user?.address).city; // TypeError

Continue the optional chain instead:

const city = user?.address?.city;

Comparisons

GoalRecommended syntaxResult when value is missing
Read an object propertyuser?.nameundefined
Read an array elementitems?.[0]undefined
Read a dynamic keysettings?.[key]undefined
Call an optional functiononSave?.()undefined; function is not called
Get the first matching array itemitems?.find(predicate)undefined
Get all matching array itemsitems?.filter(predicate)undefined if items is missing; otherwise an array

filter()[0] versus find()

ExpressionReturnsBest when
items.filter(test)[0]First item in a newly created matches array, or undefinedYou also need the full list of matches elsewhere
items.find(test)First matching item, or undefinedYou only need one match

Optional chaining versus logical AND

Before optional chaining, developers often wrote:

const name = user && user.profile && user.profile.name;

The modern equivalent is clearer:

const name = user?.profile?.name;

Unlike &&, optional chaining specifically stops only for null and undefined. This makes its intent more precise.

Take Quiz

Cheat Sheet

// Property
object?.property

// Computed property / array index
object?.[key]
array?.[0]

// Function call
fn?.()
object.method?.()
object?.method?.()

// Optional array method followed by an index
array?.filter(predicate)?.[0]

// Usually clearer for one match
array?.find(predicate)

// Fallback value
array?.[0] ?? "default value"

Rules:

  • Write ?. together; ?[0] is not valid optional chaining.
  • Use ?.[index] to protect an array access.
  • Use ?.() to protect a function call.
  • object?.method() protects object, but not a missing method.
  • object?.method?.() protects both the object and the method.
  • Optional chaining returns undefined when it encounters null or undefined.
  • It does not prevent errors from calling a non-function value.
  • Prefer find() over filter()[0] when you need only the first match.

FAQ

How do I use optional chaining to get the first array item?

Use array?.[0]. It returns the first item when the array exists and undefined when the array is null or undefined.

const first = products?.[0];

Why does ?[0] cause a JavaScript error?

Optional chaining requires a dot: ?.[0]. A standalone ? starts the conditional (ternary) operator, which requires both ? and : parts.

How do I optionally call a method on an object?

Use object.method?.() when the object exists but the method may be missing or null.

player.pause?.();

Use object?.method?.() when the object may also be missing.

Does array.filter(...)?[0] need optional chaining?

Not after a successful filter() call. filter() always returns an array, even when it is empty. Use array.filter(...)[0] if the array is guaranteed to exist. If it may not exist, use array?.filter(...)?.[0].

Should I use filter()[0] or find()?

Use find() when you need only the first matching item. It is clearer and does not create an array containing every match.

What does an optional function call return when it does not call anything?

It returns undefined.

const result = null?.();
console.log(result); // undefined

Does fn?.() prevent every function-call error?

No. It skips calls only when fn is null or undefined. If fn is 42, JavaScript still throws because 42 is not callable.

Can optional chaining replace input validation?

No. Use it for values that are legitimately optional. If a value is required, validate it and handle the error rather than silently continuing with undefined.

Take Quiz

Mini Project

Description

Build a small order lookup helper that safely reads optional arrays and optionally notifies a caller when an order is found. This mirrors API data that may not be loaded yet and callback functions that may not be provided.

Goal

Find an order by ID without errors when the order list or callback is missing.

Requirements

Use optional chaining to handle a missing orders array. Use find() to return one matching order. Return a readable default message when no matching order exists. Call an optional callback only when an order is found. Safely read an optional customer name from the matched order.

Take Quiz

Keep learning

Related questions

View more