Optional Chaining and Nullish Coalescing in Javascript
There are two new operators on the Javascript block: Optional Chaining and Nullish Coalescing. The addition of these to Javascript allow for safe deep object access (optional chaining) and default value resolution (nullish coalescing). These are incredibly exciting1 and can be effectively used together to write safe and ergonomic code for accessing objects, especially those coming from API calls or other suspect sources.
Optional Chaining
Optional chaining allows for easy access of deeply nested values within an object tree without having to check for the existence of each key along each access.
Previous to optional chaining, your deep accesses had to look something like this:
const obj = {
deeply: {
nested: {
key: 42
}
}
}
// UNSAFE: if any key does not exist, then you get a TypeError exception
obj.deeply.nested.key // 42
obj.deeply.broken.key // TypeError: undefined has no properties
// SAFER, BUT UNWIELDY
if ('deeply' in obj) {
if ('nested' in obj.deeply) {
if ('key' in obj.deeply.nested) {
obj.deeply.nested.key // 42
}
}
}
// SAFER, LESS UNWIELDY BUT STILL BAD
obj && obj.deeply && obj.deeply.nested && obj.deeply.nested.key // 42
Compare to the new optional chaining syntax (?.
), which short-circuits if a key is
undefined without throwing an error.
obj?.deeply?.nested?.key // 42 or undefined
You can also use this for optional methods:
// Setup: make two classes, one with and one without a method
class BaseAnimal {
// ... empty ...
}
class Dog extends BaseAnimal {
bark() {
console.log('woof!')
}
}
const a1 = new Animal()
const a2 = new Dog()
// Run the method if available
a1?.bark() // no output
a2?.bark() // woof!
Nullish Coalescing
Nullish coalescing is a natural complement to optional chaining. Nullish
coalescing makes it easy to set default values for variables via short-circuiting
while avoiding a common footgun of using the ||
operator. The ||
operator
operates on truthy or falsey values, which can be 0
, null
, false
, the empty
string, or undefined
(to name a few). However, the value being short-circuited
can sometimes intentionally be a falsey value, which can cause unintuitive behavior.
As an example, watch what happens when we define a simple function that takes an
optional parameter and either prints the parameter or the string default
if none
is provided:
// implementation with the "||" operator
function defaultable(option) {
// get a default value
option = option || 'default'
console.log(option)
}
// some normal examples:
defaultable() // 'default'
defaultable(42) // 42
defaultable('hi!') // 'hi!'
// things start to break here:
defaultable(0) // 'default'
defaultable(false) // 'default'
defaultable('') // 'default'
Nullish coalescing (??
) allows for slightly smarter overriding of a default
value by only considering null
and undefined
:
// implementation with the "??" operator
function defaultable(option) {
// get a default value
option = option ?? 'default'
console.log(option)
}
// some normal examples:
defaultable() // 'default'
defaultable(42) // 42
defaultable('hi!') // 'hi!'
// these work too!
defaultable(0) // 0
defaultable(false) // false
defaultable('') // ''
This is much more intuitive, as intentionally falsey values cannot trip the default value.
Putting It All Together
These two operators complement each other to create an easy way to access unknown objects from sources such as APIs. Here’s a simple (contrived) example:
const print_from_api = async () => {
const response = await fetch('https://api.example.com')
let body = await response.json()
// at this point, we don't know what body contains,
// so let's use the new syntax
console.log( body?.message ?? 'No message on body.' )
}
Browser Support
Currently, both are ECMA Stage 4 Drafts, meaning that all changes are finished
and will be included in the next ECMA standard revision. However, these features
are already available for use in most browsers. Optional chaining can be used in
78.59%
of global browsers, and nullish coalescing can be used in 78.64%
.
Notably, the Firefox Browser and Samsung Browser for Android do not support these
operators, so if you need to target these platforms you may need to use a
transpiler like Babel to get access to these.
Further Reading
- Optional Chaining on MDN
- Optional Chaining on Caniuse
- Optional Chaining TC39 Proposal
- Nullish Coalescing on MDN
- Nullish Coalescing on Caniuse
- Nullish Coalescing TC39 Proposal
1: Or rather, as exciting as we’re going to get in a pandemic.