What is Optional Chaining in TypeScript?
Optional Chaining is a feature in TypeScript that allows you to safely access deeply nested properties and methods of an object or array, without explicitly checking for the existence of each level.
- Optional Chaining Operator:
?.
is the syntax used for optional chaining in TypeScript. - Termination Behavior: If any part of the optional chain is
null
orundefined
, the chain evaluates toundefined
. - Type Inference: TypeScript infers the types correctly, accounting for the possibility of
undefined
at each level.
Syntax
The optional chaining operator ?.
can be used in three ways:
Property Access Chain
a?.b.c;
Element Access Chain
a?.b[x];
Call Chain
a?.b();
The primary objective of optional chaining is to avoid runtime errors when trying to access properties or methods of an object that might be null
or undefined
- Termination Behavior: If the base object (
a
in the above examples) isnull
orundefined
, the full expression immediately evaluates toundefined
, without trying to access any further properties or methods. - Non-Termination Behavior: If the base object is not
null
orundefined
, the property or method is accessed, and the expression is evaluated as it would be without optional chaining.
Examples
Without Optional Chaining
const user = {
name: 'Sanjana',
address: {
street: '435 sherbrook',
city: 'British Columbia',
state: 'BC'
}
};
// We have to do multiple null/undefined checks
const city = user && user.address && user.address.city; // British Columbia
const zip = user && user.address && user.address.zip; // undefined
With Optional Chaining
const user = {
name: 'Sanjana',
address: {
street: '435 sherbrook',
city: 'British Columbia',
state: 'BC'
}
};
// Can safely access deeply nested properties
const city = user?.address?.city; // British Columbia
const zip = user?.address?.zip; // undefined
Using Optional Chaining with Functions
When using optional chaining with functions, the function is only called if it is defined.
const user = {
name: 'Sanjana',
getName: () => 'Sanjana'
};
// Calls the function getName() only if it's defined
const name = user?.getName?.(); // Sanjana
const userWithoutFunction = {
name: 'NoUser'
};
// Returns undefined without throwing an error
const nameWithoutFunction = userWithoutFunction?.getName?.(); // undefined
Here in userWithoutFunction has no property called getName so it will return to undefined.