Borislav Hadzhiev
Sun Feb 13 2022·3 min read
Photo by Meiying Ng
The question mark dot (?.) syntax is called optional chaining in TypeScript
and is like using dot notation to access a nested property of an object, but
instead of causing an error if the reference is nullish, it short-circuits
returning undefined
.
type Person = { address?: { country?: string; }; name?: { first?: string; }; }; const person: Person = { address: { country: 'Chile', }, }; console.log(person.address?.country); // 👉️ "Chile" console.log(person.name?.first); // 👉️ undefined
We created a type where the the address
and name
properties are optional.
The first console.log
statement uses the
optional chaining (?.)
operator to access the address.country
property on the person
object.
Because the address.country
property exists on the person
object, its value
gets logged to the console.
The second example uses the optional chaining (?.) operator to access the
name.first
property on the person
object, but because the property does not
exist on the object, the optional chaining (?.) operator returns undefined
.
null
or undefined
) reference, the optional chaining operator (?.) short-circuits returningundefined
instead of throwing an error.Had we not used the optional chaining operator, we would get an error because
we're trying to access a property on an undefined
value.
type Person = { address?: { country?: string; }; name?: { first?: string; }; }; const person: Person = { address: { country: 'Chile', }, }; // ⛔️ ERROR: Cannot read properties of undefined (reading 'first') console.log(person.name.first); // 👉️ undefined
We didn't use the optional chaining (?.) operator to short-circuit in case the
name
property was not set, so we got an error.
You might have used the logical AND (&&) operator to get around this in the past.
type Person = { address?: { country?: string; }; name?: { first?: string; }; }; const person: Person = { address: { country: 'Chile', }, }; console.log(person.name && person.name.first); // 👉️ undefined
We used the
logical AND (&&)
operator to check if accessing the name
property on the person
object
returns a truthy value, if it does, we can try to access the first
property on
the name
object.
null
or undefined
.The optional chaining operator can also be used to access an array element at a
specific index or short-circuit if the reference is null
or undefined
.
type Person = { numbers?: { low?: number[]; }; }; const person: Person = {}; console.log(person.numbers?.low?.[0]); // 👉️ undefined
The low
property could be undefined
, so trying to access the array element
at index 0
on an undefined
value would throw an error unless we use the
optional chaining (?.) operator to short-circuit if the reference is
undefined
.
If the property is populated on the object, the optional chaining operator returns the specific value in the array.
type Person = { numbers?: { low?: number[]; }; }; const person: Person = { numbers: { low: [1, 2, 3], }, }; console.log(person.numbers?.low?.[0]); // 👉️ 1
The optional chaining (?.) operator can also be used to call a function if its
value is not equal to null
or undefined
.
function logger(callback?: (msg: string) => void) { callback?.('hello'); } logger(console.log); // 👉️ "hello"
Trying to call the callback
parameter would cause an error if it isn't
provided, so we used the optional chaining (?.) operator to check if the
reference is not null
or undefined
before calling the function.
If the parameter is not provided, the operator would just short-circuit
returning undefined
instead of calling the function.