Question

Optional Chaining in TypeScript: Does TypeScript Support `?.` and What Is It Called?

Question

In TypeScript, is the ?. operator supported for safe property access?

For example:

const thing = foo?.bar;

Is this equivalent to something like:

const thing = foo ? foo.bar : null;

Also, what is the standard or most commonly used name for this operator? It can be difficult to search for because the symbol is so short.

Short Answer

By the end of this page, you will understand that TypeScript does support ?., the operator is commonly called optional chaining, and it is used to safely access properties, call methods, or read array elements when a value might be null or undefined. You will also see how it differs from a normal ternary check and how developers use it in real TypeScript code.

Concept

TypeScript supports the ?. operator, and its common name is optional chaining.

Optional chaining lets you safely continue an expression only if the value on the left is not null or undefined. If the value is null or undefined, the whole expression stops and returns undefined instead of throwing an error.

For example:

const city = user?.address?.city;

This means:

  • If user exists, try to read address
  • If address exists, try to read city
  • If either user or address is null or undefined, return undefined

This matters because real programs often deal with missing data:

  • API responses may omit fields
  • Optional configuration values may not exist
  • Callback functions may or may not be provided
  • Nested objects may be partially loaded

Without optional chaining, code becomes repetitive:

const city = user && user.address && user.address.city;

Or more explicit:

const city = user ? (user.address ? user.address.city : undefined) : undefined;

Optional chaining makes this much cleaner.

One important detail: foo?.bar is not exactly the same as:

foo ? foo.bar : null

Differences:

  • foo?.bar checks specifically for null or undefined
  • foo ? foo.bar : null checks for all falsy values, such as 0, "", and false
  • foo?.bar returns undefined when access stops, not null

So optional chaining is more precise and usually safer than a truthiness check.

Mental Model

Think of optional chaining like walking through a building with automatic doors.

  • If the next door exists and opens, you keep going
  • If you reach a missing or locked door (null or undefined), you stop safely
  • Instead of crashing into the wall with an error, you simply end up with undefined

Example:

const result = company?.department?.manager?.name;

You are trying to walk through:

  • company
  • department
  • manager
  • name

If any step in that path is missing, the process stops there safely.

Without optional chaining, you would have to manually check every door before opening the next one.

Take Quiz

Syntax and Examples

Basic syntax

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

Optional chaining can be used in three common ways:

1. Safe property access

type User = {
  name: string;
  profile?: {
    bio?: string;
  };
};

const user: User = {
  name: "Ava"
};

const bio = user.profile?.bio;
console.log(bio); // undefined

Here, profile is optional. If it does not exist, user.profile?.bio safely returns undefined.

2. Safe array access

const items = ["a", "b", "c"];
const first = items?.[0];
console.log(first); // "a"

This is especially useful when the array itself might be missing.

const items2: string[] | undefined = undefined;
const first2 = items2?.[0];
console.log(first2); // undefined

3. Safe method call

type Logger = {
  log?: (message: string) => void;
};

const logger: Logger = {};
logger.log?.("Hello"); // No error

If log exists, it is called. If not, nothing happens and the expression returns undefined.

Comparing with a ternary

const thing = foo?.bar;

This is closer to:

const thing = foo == null ? undefined : foo.bar;

It is not the same as:

const thing = foo ? foo.bar : null;

Because that version treats 0, false, and "" as missing, which optional chaining does not.

Step by Step Execution

Consider this example:

type ApiResponse = {
  user?: {
    contact?: {
      email?: string;
    };
  };
};

const response: ApiResponse = {
  user: {
    contact: {
      email: "ava@example.com"
    }
  }
};

const email = response.user?.contact?.email;
console.log(email);

Step by step:

  1. response.user is checked

    • It exists, so evaluation continues
  2. response.user.contact is checked

    • It exists, so evaluation continues
  3. response.user.contact.email is read

    • It exists and equals "ava@example.com"
  4. email gets the value "ava@example.com"

Now change the data:

const response2: ApiResponse = {};
const email2 = response2.user?.contact?.email;
console.log(email2);

Step by step:

  1. response2.user is checked

    • It is undefined
  2. Because optional chaining is used, evaluation stops immediately

  3. contact and email are not accessed

  4. email2 becomes undefined

This prevents a runtime error like:

Cannot read properties of undefined

Real World Use Cases

Optional chaining appears often in real applications where data may be incomplete.

API responses

const avatarUrl = response.data?.user?.profile?.avatarUrl;

APIs often return partial or optional fields.

Form validation

const errorMessage = errors.email?.message;

Validation libraries often store errors only for fields that failed.

Optional callbacks

props.onSave?.();

A component may receive a callback prop, but it may not always be provided.

Configuration objects

const timeout = config.network?.timeout;

Different environments may define different config sections.

Browser or platform features

const language = navigator.languages?.[0];

Some platform APIs may not exist in every runtime.

Database or nested domain models

const managerName = employee.department?.manager?.name;

Large object graphs often contain optional relationships.

Take Quiz

Real Codebase Usage

In real TypeScript projects, optional chaining is commonly used with a few important patterns.

Reading nested data safely

Developers often consume JSON from APIs where many fields are optional.

const zipCode = order.customer?.address?.zipCode;

Optional function execution

This is a common pattern for event handlers, hooks, and callbacks.

options.onComplete?.(result);

Pairing with nullish coalescing

Optional chaining is often combined with ?? to provide a default value.

const theme = settings.userPreferences?.theme ?? "light";

This means:

  • Try to read theme
  • If the result is null or undefined, use "light"

Guarding without deep nesting

Instead of many if statements:

if (request.user && request.user.session && request.user.session.id) {
  // use id
}

Developers often write:

const sessionId = request.user?.session?.id;
if (sessionId) {
  // use id
}

Cleaner UI rendering

In frontend code:

const displayName = user.profile?.displayName ?? user.name;

This keeps rendering logic concise while still being safe.

Logging and error handling

console.error(error.response?.data?.message ?? "Unknown error");

This avoids crashes while extracting useful information from uncertain objects.

Common Mistakes

1. Treating ?. as a general falsy check

Broken assumption:

const result = value?.name;

Some beginners think this stops when value is 0, false, or "". It does not. It only stops for:

  • null
  • undefined

2. Assuming it returns null

const name = user?.profile?.name;

If the chain stops, the result is undefined, not null.

If you need a fallback:

const name = user?.profile?.name ?? "Anonymous";

3. Using it where the left side cannot be nullish

const user = { name: "Ava" };
const name = user?.name;

This is valid, but unnecessary if user is guaranteed to exist.

4. Confusing ?. with &&

Old pattern:

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

Better modern pattern:

const name = user?.profile?.name;

But remember: && uses truthiness, while ?. uses nullish checks.

5. Forgetting that only one step is protected

Broken code:

const value = user?.profile.name;

If user exists but profile is undefined, this still throws.

Safer version:

const value = user?.profile?.name;

6. Expecting optional chaining to fix all invalid operations

Broken code:

const result = maybeNumber?.toFixed(2);

This is only safe if maybeNumber may be null or undefined. It does not protect you from wrong types.

For example, if maybeNumber is a string, you still have a type problem.

7. Overusing it instead of validating important data

Optional chaining is useful, but if a value must exist for your program to work, validate it clearly instead of silently continuing.

if (!config.apiKey) {
  throw new Error("Missing API key");
}

Comparisons

ConceptWhat it checksResult when missingNotes
foo?.barfoo is null or undefinedundefinedPrecise nullish-safe access
foo ? foo.bar : nullfoo is truthynullTreats 0, false, "" as missing
foo && foo.barfoo is truthyreturns foo if falsyOlder JavaScript pattern
foo!.barNo runtime checkaccesses directlyNon-null assertion; tells TypeScript to trust you

Optional chaining vs non-null assertion

const name1 = user?.profile?.name;
const name2 = user!.profile.name;
  • ?. is safe at runtime
  • ! is not a runtime safety feature
  • ! only tells the TypeScript compiler to stop warning you

Optional chaining vs nullish coalescing

const name = user?.profile?.name ?? "Anonymous";
  • ?. safely reads a value
  • ?? provides a fallback if that value is null or undefined

They are often used together.

Take Quiz

Cheat Sheet

// Property access
obj?.prop

// Array or index access
obj?.[index]

// Method call
obj?.method()

Key rules

  • ?. is called optional chaining
  • It stops only for null or undefined
  • If it stops, the result is undefined
  • It can be used for properties, indexes, and method calls
  • It does not treat 0, false, or "" as missing

Good examples

const city = user?.address?.city;
const firstItem = list?.[0];
callback?.("done");

Common pairing

const city = user?.address?.city ?? "Unknown";

Rough equivalent

const city = user == null ? undefined : user.address;

Not equivalent to

const city = user ? user.address : null;

Because that uses truthiness, not nullish checks.

FAQ

What is the ?. operator called in TypeScript?

It is called optional chaining.

Does TypeScript support optional chaining?

Yes. TypeScript supports optional chaining and uses the same ?. syntax as modern JavaScript.

Is foo?.bar the same as foo ? foo.bar : null?

No. Optional chaining checks only for null and undefined, and it returns undefined if access stops.

What does optional chaining return if something is missing?

It returns undefined.

Can I use optional chaining with methods?

Yes.

logger?.log?.("Hello");

Can I use optional chaining with arrays?

Yes.

const first = items?.[0];

Should I always use optional chaining?

No. Use it when a value may legitimately be missing. If a value is required, validate it explicitly.

What should I search for to learn more about ?.?

Search for TypeScript optional chaining or JavaScript optional chaining.

Take Quiz

Mini Project

Description

Build a small TypeScript utility that reads profile information from possibly incomplete user data. This demonstrates how optional chaining helps when working with API-style objects where some nested fields may be missing.

Goal

Create a function that safely reads nested user information and returns sensible fallback values.

Requirements

  • Define a TypeScript type for a user with optional nested profile and contact fields.
  • Create at least two example users, including one with missing nested data.
  • Write a function that returns the user's display name and email safely.
  • Use optional chaining to access nested properties.
  • Use nullish coalescing to provide default values when data is missing.
Take Quiz

Keep learning

Related questions

View more