Optional Chaining for Javascript - ES proposal
We saw nullish coalescing yesterday, today let's see optional chaining another awesome ESnext feature. It is so awesome not to talk about.
Just like nullish coalescing, optional chaining helps us handle undefined
and null
cases. let's consider the following example
let company = {
name: 'Github',
revenue: 2000,
users: [
{ name: 'John', handle: '@john' },
{ name: 'doe', handle: '@doe' },
],
getUserNames() {
return users.map(user => user.name)
},
}
to access the values of this object, if they or the object can be undefined
or null
we would normally do the following.
const companyName =
company !== undefined && company !== null ? company.name : undefined
In contrast with optional chaining we can do
const companyName = company?.name
The Syntax
obj?.prop // optional static property access
obj?.[expr] // optional dynamic property access
func?.(...args) // optional function or method call
Let's see how we can handle multiple ways of accessing properties of an object.
- Static
- Dynamic
- Function Call
- Dom access
Static Properties
let company = {
name: 'Github',
revenue: 2000,
users: [
{ name: 'John', handle: '@john' },
{ name: 'doe', handle: '@doe' },
],
getUserNames() {
return users.map(user => user.name)
},
}
// with optional Chaining
const companyName = company?.name
// without optional Chaining
const companyName =
company !== undefined && company !== null ? company.name : undefined
Dynamic Properties
let company = {
name: 'Github',
revenue: 2000,
users: [
{ name: 'John', handle: '@john' },
{ name: 'doe', handle: '@doe' },
],
getUserNames() {
return users.map(user => user.name)
},
}
// with optional Chaining
const companyName = company?.['name']
// without optional Chaining
const companyName =
company !== undefined && company !== null ? company['name'] : undefined
Function calls
let company = {
name: 'Github',
revenue: 2000,
users: [
{ name: 'John', handle: '@john' },
{ name: 'doe', handle: '@doe' },
],
getUserNames() {
return users.map(user => user.name)
},
}
// with optional Chaining
company.getUserNames?.()
// without optional Chaining
const companyName =
company !== undefined &&
company !== null &&
Object.prototype.hasOwnProperty('getUserNames') &&
typeof company.getUserNames === 'function'
? company['name']
: undefined
Dom access
Optional Chaining supports DOM and its methods, so we can do stuff like this
const val = document.querySelector('input#name')?.value
Optional Chaining will always return undefined
if the expression fails.
const value = company?.name
// 'value' will be undefined if company is undefined.
So we can pair optional chaining with nullish coalescing to handle those cases.
const value = company?.name ?? 'default name'
// 'value' will be 'default name' if either the company or name is undefined or null.
To wrap it up with a complete example
let company = {
name: 'Github',
revenue: 2000,
users: [
{ name: 'John', handle: '@john' },
{ name: 'doe', handle: '@doe' },
],
getUserNames() {
return users.map(user => user.name)
},
}
// Static access with default value
const value = company?.name ?? 'default name'
// Dynamic access with default value
const companyName = company?.['name'] ?? 'default value'
// Function call
company.getUserNames?.()
Optional chaining and nullish coalescing brings a lot of benefits, by reducing the complexity and making code readable. Give them a try and let me know your opinions in comments below.
You can use the following babel plugins to use them today.
Follow me on twitter