Optional chaining in JavaScript and TypeScript
When accessing data located deep in object structure, we used to have to check if every parent object exists. Let's say we have this simple object which contains other objects:
const data = {
someObject: {
a: 1,
b: 2,
c: 3,
},
someOtherObject: {
a: 1,
},
};
If we would access existing property, everything works fine
❯ data.someObject.c
3
The same if we want to access non-existing property of existing object
❯ data.someObject.d
undefined
But what about a situation, when we try to access a property of an object that may, or may not exist?
❯ data.nonExistingObject.a
Uncaught TypeError: data.nonExistingObject is undefined
To handle this type of error, we would need to first check if object exists. It's ok if we have such a simple case like in the example. But what if we have a deep nested object? The condition we would need to use in if
statement would be really long and not really readable.
And there optional chaining operator comes in handy.
Optional chaining operator
From MDN:
The optional chaining operator (
?.
) enables you to read the value of a property located deep within a chain of connected objects without having to check that each reference in the chain is valid.
Syntax:
obj.val?.prop;
obj.val?.[expr];
obj.arr?.[index];
obj.func?.(args);
So how can we fix our example? Just add ?
after property that may be nullish
❯ data.nonExistingObject?.a
undefined
That way we don't get any errors, just an information that this values doesn't exist.
Other use cases
But can this operator be used also for use cases other than just simple object? Of course. We can use it also with arrays and functions.
Arrays
const data = {
array: [1, 2, 3],
};
❯ data.array[0]
1
❯ data.nonExistingArray[0]
Uncaught TypeError: data.nonExistingArray is undefined
❯ data.nonExistingArray?.[0]
undefined
Functions
const data = {
someFunction: (a) => a * 2,
};
❯ data.someFunction(2)
4
❯ data.nonExistingFunction(2)
Uncaught TypeError: data.nonExistingFunction is not a function
❯ data.nonExistingFunction?.(2)
undefined