ProgrammingFrontend Developer

How does the optional chaining mechanism work in TypeScript? What problems does it solve and in what cases can its use lead to errors in practice?

Pass interviews with Hintsage AI assistant

Answer.

The optional chaining mechanism (?.) was introduced in JavaScript for convenient and safe access to properties and methods of objects that may not be defined. In TypeScript, it has become especially useful as it helps avoid runtime errors related to accessing properties or methods of undefined or null.

Background

Before the advent of optional chaining, developers had to manually check the existence of each level of object nesting, making the code long and hard to read:

if (obj && obj.a && obj.a.b) { // ... }

Problem

Accessing nested properties on an undefined object can lead to a runtime error: Cannot read property 'x' of undefined. Additionally, long chains of checks complicate code maintenance and readability.

Solution

Optional chaining (?.) allows accessing nested properties, methods, or array elements, automatically returning undefined if any part of the chain is null or undefined.

Example:

interface User { name: string; address?: { city?: string; }; } const user: User = { name: 'Ivan' }; console.log(user.address?.city); // undefined

Key features:

  • Allows writing compact, safe, and clear code.
  • Works with property, method, and array index access.
  • The return type is T | undefined, which is accounted for by the TypeScript compiler, helping to avoid errors.

Tricky Questions.

Can optional chaining be used on the left side of the assignment operator? For example: user.address?.city = 'Moscow'?

No, optional chaining cannot be used in the left expression of an assignment; this will result in a compilation error. Optional chaining works only for reading, not for writing.

Can optional chaining be used to call a method if the object itself may be undefined? For example: user?.logInfo()?

Yes, if the object up to the method call can be undefined/null, then calling user?.logInfo() will not throw an error and will simply return undefined if user is not defined.

user?.logInfo(); // if user is defined, logInfo will be called, otherwise nothing happens

What is the difference between optional chaining and the '&&' operator in the old style, for example: user && user.address && user.address.city?

Optional chaining is shorter, works for all types (including methods and arrays), and TypeScript accounts for it during type checking. Importantly, when using the '&&' operator, you might accidentally get a nested value instead of true/false or undefined. Optional chaining guarantees that you get either the expected type or undefined, which is accounted for in type inference.

Common Errors and Anti-Patterns

  • Expecting that optional chaining "creates" nested objects during assignment — this is not the case.
  • Using optional chaining when accessing variables that by type can never be undefined/null (unnecessary and useless code).
  • The habit of thoughtlessly applying optional chaining everywhere, which complicates further code maintenance.

Real-Life Example

Negative Case

The code uses long optional chaining chains even where, according to business logic, the variables are always defined:

order?.customer?.address?.city = 'London';

Pros:

  • Protects against possible errors if the properties are actually undefined.

Cons:

  • Assignment will not happen if any of the properties are missing, with no notification or error handling; introduces "hidden" logic, complicating the code.

Positive Case

Optional chaining is used only when working with external data or in places where values may genuinely be undefined:

const city = apiResponse?.info?.location?.city || 'Unknown';

Pros:

  • Safely works even with incomplete or unexpectedly changed objects without throwing exceptions.
  • Easy-to-read and maintain code.

Cons:

  • If it's necessary to understand why a value is missing, explicit error handling must be performed.