9 MIN READ
   //   Jan 10, 2020

Optional Chaining Operator in JavaScript

mayuri.papat

Property chaining challenges: 

Working with JSON structure involves a lot of conditional checks, accessing nested properties of JSON, and checking multiple And operators (&&) to verify whether the given value exists or not. If it does exists then retrieve the value of that attribute.

While accessing or mapping an object’s  properties we came across this error:

TypeError: Cannot read property ‘********’ of undefined.

In JavaScript, we use the && operator as a fallback option.

The cool thing about this operator is that the second expression is never executed if the first expression is false. This has some practical applications, for example, to check if an object is defined before using it we can first check if an object exists, and then try to get one of its properties:

const car = { color: ‘green’ }
const color = car && car.color;

Even if a car is null, we don’t get errors and the colour is assigned a null value.

We can go down multiple levels:

const car = { }
const colorName = car && car.color && car.color.name

In some other languages, we use the && operator to determine true or false, since it’s usually a logic operator. But not in JavaScript and this allows us to do some really amazing things.

In JavaScript, an object can have a very different nested structure of objects. Let’s look at  an example: 

Obj can have a different set of properties during runtime:

//1st 
Const obj = {
Prop1: {
//…
Prop2: {
//…
Value: ‘Some value’
}
}
};

// 2nd
Const obj = {
//…
Prop1: {
//nothing here
}
};

Thus we have to manually check the property’s existence:

If (obj &&
    obj.prop1 != null &&
    obj.prop1.prop2 != null) {
     let result = obj.prop1.prop2.value;
}

That’s a lot of overlapping code. 

Performing checks on every single field of JSON becomes tedious This is where the  Optional Chaining feature of JavaScript comes in.

Optional chaining, as a part of ES2020, changes the way properties are accessed from deep objects structures.

What is Optional Chaining?

Optional chaining allows us to check if an object exists before trying to access its properties. In simple words, we need not validate for null or undefined while accessing each property on the hierarchy.

“?.” is used as the optional chaining operator.

Syntax :

obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)

Let’s see how we can handle multiple ways of accessing the properties of an object:

let street = user && user.address && user.address.street

We can soon rewrite the above line as:

Let street = user?.address?.street

The basic rule is if any of the values after ‘a?’ are null or undefined, then the statement will return null or undefined without throwing an error.

An alternative for not repeatedly adding the ‘?’ operator at every level provided we are confident that every user has an address but uncertain if the user exists is:

let street = user?.address.street

We need to check the existence of objects or arrays prior to accessing its properties and if while iterating over an array too. 

For example:

const data= [ ];

data.map( ( item, index )=> {
return (
	<div>{item}</div>
)
}

If the data variable is null or undefined?

We would get an error -  type error: cannot read property ‘data’ of undefined.

The solution to this is to check whether our data exists and isn’t empty, this can be determined by checking the array.length.

if(data && data.length > 0){
	data.map(item => <div>{item}</div>)
}

Or

data &&  data.length > 0  && data.map( item => <div> {item} )</div>

We can improve the code with a simple question mark.

data?.map( item => <div> {item }</div>)

Let's take another example:

Let company = {
	name: ‘Facebook,
	revenue : 2000,
	users: [
		{ name: ‘John’, email: ‘[email protected]’ },
		{ name: ‘Jane’, email: ‘[email protected]’ },
	],
getUserName = () =>{
		return users.map(user => user.name)
	},
};

In order to access the values of this object (the object can be undefined or null)

const companyName = company !== undefined && company !== null ? company.name : undefined;

Using optional chaining we can:

const companyName = company?.name

Using optional chaining with function calls causes the expression to automatically return ‘undefined’ instead of throwing an exception if the method is not found:

company.getUserNames?.()

Optional chaining brings a lot of benefits, by reducing the complexity and making the code readable.