What is Optional Chaining?
It's a new addition that has been added to ES2020 that allows us to check for object properties to make sure that they're not undefined or null.
What the problem is
Before, to check if an object's property was undefined, we could do something like this:
let nameLength = db.student.name.length
Now, the problem is if db, student, or name is undefined it would throw a type error so let's try it another way.
let nameLength;
if(db && db.student && db.student.name) {
nameLength = db.student.name.length
}
You could also use the ternary operator
const nameLength =
(db
? (db.student
? (db.student.name
? db.student.name.length
: undefined)
: undefined)
: undefined);
Okay, the last two examples are less error-prone but it doesn't exactly help readability so let's introduce optional chaining, shall we.
Introducing Optional Chaining
The problems have been presented so let's use the alternative to refactor the first example.
let nameLength = db?.student?.name?.length
It is characterized by the ?. operator and if db, student, or name is undefined then it won't throw an error, instead, nameLength will just be undefined.
Short-circuiting
First and foremost, what is short-circuiting?
Let's take a look at the || logical operator
In JavaScript, it will evaluate from left to right and if it finds a truthy value then it will "short-circuit" and not even look at the second operand.
true || false
Short-circuiting in optional chaining
Since it evaluates from left to right, if we look at the example below
let user = null;
let count = 0;
user?.increase(count++);
console.log(count); // 0
The operator ?. will immediately "short-circuit" and not check the rest if the user doesn't exist.
Using square brackets [ ]
const optionName = 'optional setting';
const optionLength = db?.student?.preferences?.[optionName].length;
If the option name is undefined then opitionLength will just be undefined and if it is not undefined it will return the value
Function invocation
Similar to accessing the property with a square bracket, you can also invoke a function
const adminOption = db?.student?.validateSomeAwesomeFunction?.().option;
nullish coalescing ?? operator
Optional Chaining can be used with the nullish coalescing ?? operator when you need a default value.
const object = { id: 13, names: { first: 'Natalie', last: 'Smith' }};
const bio = object?.names?.bio ?? 'Tell us about yourself';
As you can see, since the property bio doesn't exist on the object, we just result back to the defaulted value.
Caveats
Don't overuse optional chaining as it only allows for us to check to see if a property value is undefined/null. If we did user?.favorites and the user is not defined then it will throw an error.
Equality Checks
Let's take a look at the following example
if(foo && bar && foo.opitionOne === bar.opitionTwo) {...}
and convert it to
if(foo?.opitionOne === bar?.opitionTwo) {...}
In the first case without optional chaining, the condition will not be true unless both foo and bar are truthy. However, in the second case, if foo and bar are null, it will be truthy because foo and bar will return undefined, and thus, this can lead to an unexpected equality check and bugs.
Operator precedence
First and foremost, what is the operator precedence?
It determines the order in which operators(|| && ===) are evaluated much like CSS selectors(.class, #id, etc..) whichever one has higher precedence it will be evaluated first.
One thing to note is optional chaining has higher precedence than &&. So when going in to replace the && with optional chaining for an equality check and since && has lower precedence than ?. it might introduce an unexpected outcome especially since ?. will return undefined if it's not there.
Conclusion
Thank you for reading and if I missed something in this post please comment down below, I'm not an expert so feedback is always appreciated.
If you would like to buy me a coffee ☕️ that would be deeply appreciated as I am always tired 😴
cover image from https://daqxzxzy8xq3u.cloudfront.net/wp-content/uploads/2019/10/21104843/javascript-optional-chaining.jpg
Top comments (2)
I'd add in the Function invocation section a note on how this could throw an error if for some reason we could expect the value to be false. Specially if one comes from using something like
student.validateSomeAwesomeFunction && student.validateSomeAwesomeFunction();
(I think it can be more common in passed props on React, as it happened to me)
Nice one, i have been waiting for this since, this is available in Angular Html template and i love it