Optional chaining without ES11? - Safely Access - Javascript Tips & Tricks

  Diego Artiles   •     5 Min

As you know, every year EcmaScript releases a new version to improve JavaScript, these improvements have made our lives easier, and have allowed us to do things that we could not do with the language natively before, or that required many lines of code.

In this post we will talk a little bit about optional chaining (implemented in ES11/ES2020 version) instead of all the improvements introduced. For those who do not know, optional chaining is a functionality that allows us to safely access properties of objects in javascript, avoiding common errors such as "Can not read property foo of undefined".

Suppose we want to get the amount of apples from fruit objects has only bananas. Let's see what result we get with and without "optional chaining". I leave you an example

const fruits =  {
	bananas: {
        quantity: 12
    }
}

fruits.apples.quantity // ERROR: Cannot read property 'quantity' of undefined

// With optional chaining
fruits.apples?.quantity // undefined

As I mentioned earlier, this functionality was introduced in ES11, but what alternatives were there before for this?  Let's see some of them 🚀

"Optional chaining" with OR operator

As we know, javascript parentheses are used to evaluate an expression, so for the previous example we can check if "apple" exists in the fruits object before accessing the next property.

To do that we can use the OR operator like this.

(fruits.apples || {}).quantity // undefined
Safely access with OR operator

In this example, the operator will return the value of apples if it isn't falsy value, otherwise {}

In other words, we have (undefined || {}).quantity literally, so it is safe to access "quantity" from an empty object and not from an undefined value.

"Optional chaining" with AND operator

This is the most common option and perhaps the longest. Using the same example with the AND operator, it looks like this:

fruits.apples && fruites.apples.quantity // undefined
Safely access with AND operator

Safely access to properties with default parameters

If we want to safely access the property of an object through a function parameter, we can use the previous alternatives or use the default parameter (implemented in ES6).

I leave you an example:

const fruits =  {
	bananas: {
        quantity: 12
    }
}

const getFruitQuantity = (fruit = {}) => {
    return fruit.quantity
}

getFruitQuantity(fruits.apples) // undefined

Useful functions for more complex objects.

With some of these alternatives we can build a function that helps us access more complex object properties.

Using the fruits object:

const fruits =  {
	bananas: {
        quantity: 12
    }
}


I leave you some examples found on the net:

get = function(obj, key) {
    return key.split(".").reduce(function(o, x) {
        return (typeof o == "undefined" || o === null) ? o : o[x];
    }, obj);
}

/* Usage */
get(fruits, 'apples.quantity') // undefined
Click here to go to the source
const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce(
      (obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : null),
      nestedObj
    );
};

/* Usage */
getNestedObject(fruits, ['apples', 'quantity']) // null
Click here to go to the source

Is it just to access objects?

Throughout this post, I have only mentioned the properties of objects, so does it work for objects only?

The answer is NO. 🤓

We can use both the mentioned alternatives and the "optional chaining", to access elements of arrays or execute functions in a safe way. I leave you some examples:

const someObject = null

// OR operator
((someObject || {}).someFunction || function(){} )() // undefined

// AND operator
typeof someObject === 'object' && typeof someObject.someFunction === 'function' && someObject.someFunction() // undefined

// Optional Chaining
someObject?.someFunction?.()
Function Invocation
const someObject = null
const someArray = null

// OR operator
((someObject || {}).someArray || [])[0] // undefined

// AND operator
typeof someObject === 'object' && typeof someObject.someArray === 'object' && someObject.someArray[0] // undefined

// Optional Chaining
someObject?.someArray?.[0]
Array index.

Conclusion

As you can see of the three ways learned, the longest is with the AND operator, but none is as short as the "optional chaining".

These types of errors are common and frequent, so it is necessary to know how to handle and avoid them.

If you find inconsistencies in the writing of this post or if on the contrary it is okay, please let me know in the comments section, English is not my native language but I try to express myself as best I can 🤗

Do you like microfrontends or have you heard of them? Be aware that I will talk about them soon