Update: Optional Chaining is finally in Stage 4!! Which means it is part of the ES2020 specification. It has also already made it to TypeScript v3.7.
Here's the repo with all the info you need.
What is it?
Optional Chaining allows us to check if an object exists before trying to access its properties. Some other languages have something similar. C#, for example, has a Null Conditional Operator that behaves very similarly as the proposed Optional Chaining.
Why do we need it?
Have you ever had to check for the existence of objects or arrays before accessing its properties? If you forget, it may look a little bit like this:
if(specimen && specimen.arms && specimen.arms.length > 2)
console.log("This is probably an alien");
The reason why we do these checks is because in JavaScript allows for anonymous objects that don't necessarily have a structure or schema. Therefore if we don't check for parents in an object tree, we get a lot of errors that look like this:
Because, at least in the case of the error, specimen
does exist, but it does not have an arms
property. Therefore, we tried to get length
of something that was undefined
.
So, what's the proposal?
Instead of all that, we can chain optional checks like this:
if(specimen?.arms?.length > 2)
console.log("This is probably an alien");
However, keep in mind that the Optional Chaining operator is ?.
not ?
- this means that when using it to access an item in an array, it will look like this instead:
var firstArm = specimen?.arms?.[0]; //CORRECT
var secondArm = specimen?.arms?[1]; //WRONG
Similarly, when using it to check for the existence of functions:
var kickPromise = specimen?.kick?.(); //CORRECT
var punchPromise = specimen?.punch?(); //WRONG
In this case, we check if kick
exists before calling it as a function!
How does it work?
The operator checks if whatever is to the Left-Hand Side of ?.
is null
or undefined
. If it is, then the expression short-circuits and returns undefined
. Otherwise, the expression continues to evaluate as if nothing is wrong.
When can I use it?
Well, it is still a proposal so it's not in Vanilla JavaScript just yet. However, it is usable with Babel!
To stay up to date with the status of the proposal, as well as to have a more in-depth understanding and to check some examples, you should check their GitHub repo! You can also find the specs here, but I won't get into that since most of that document goes way over my head 😅
Thank you!
You're welcome! ❤️
Top comments (41)
I don't know about the syntax (func?.() and arr?.[0] is kind of weird) but it would be really useful!
Yeah, you are not alone in that. That syntax of those seems to be the main reason this is still in Stage 1. It's likely that will change before hitting Stage 2!
JS is looking more like Swift every day. 👍
Swift masterrace
Typescript already has this. Would be nice in vanilla Js too
Typescript does not have it. They won't implement anything in stage 1. github.com/Microsoft/TypeScript/is...
I have used it in Angular isn't it Typescript?
That's from Angular template syntax. It's called safe navigation operator. Not from TypeScript.
So apparently there has been a lengthy, 3 years long discussion about adding this to TS, which sometimes gets heated.
But it seems from the last comment on the thread that it actually has not been implemented in TypeScript, and it wont be implemented until the ES committee locks down its semantics :/ That is, unless there's something I'm missing?
It is present in CoffeeScript
In C# it is also called the Elvis-operator because it looks a bit like two eyes under curvy hair.
Very useful feature, and better than including lodash get in my code. Although, hasn't the optional chaining operator has been in Stage 1 for a while? Is there something to indicate this feature is moving up in the world?
Yeah, it has been in Stage 1 for a long while. From what I can gather in these meeting notes from last year there is still no consensus on the exact syntax, and some people are still discussing the scope of the proposal.
Short version is, function call
?.()
and bracket access?.[n]
parts are not loved because the syntax. The three operators?.
,?.(
, and?.[
don't do the exact same thing, so it leads to confusion.I'd say the fact that there is an active discussion about this feature in the TC39 meetings indicate that this feature is moving up - but to be honest I could be wrong. I'm only slightly familiar with the process.
Didn't know this exists in c#! Neat
C# is awsome, have a look here: docs.microsoft.com/en-us/dotnet/cs...
There is also async await for years now... ;)
C# is a fantastic language :D
I'm a beginner in C# and recently I've had to make null check nested fields and now knowing chaining operators, it's much easier and simplifies my code :)
Wow this is awesome. I've wanted this forever. The next thing I would want is this for arbitrary conditionals such as findIndex. If findIndex returns -1 consider it errored.
Wooo fun!
This seems like a useless way to silence errors to me.
(specimen?.arms?.length > 2)
will return false ifspecimen
is undefined, ifarms
is undefined, ifarms
happens to be a boolean for some reason, or ifspecimen.arms.length
is 1.. wouldn't you need to treat these things all differently? So what's the point of this?It all depends on the situation. Sure, sometimes you need to check if you have
specimen
orarms
because you would have to handle those scenarios differently. Say, notifying the user that they need to have aspecimen
in the first place, or populate it yourself.But if you have
specimen
and all you need to do is to check if it is an alien or not, this syntax fits like a glove. I don't need to check and handle every single property before the one that I actually need, that's why in JavaScript we have a bunch of if conditions that look like this:And as far as
arms
being a Boolean, this proposal is not trying to fix type issues with the language. For that kind of problems, it would be better to look at TypeScript, or Flow.I suppose you're right, it is inconvenient to have to do that. But I feel like this problem can be solved with a better design in the object structure. For this specific example, why would the object not just have a static boolean property like
specimen.alien
or something? Following a better design guideline like the Law of Demeter would solve this, right? It seems like this proposal may encourage (or at least fail to discourage) messy object structures. I only brought up the boolean example cause this is solving a common TypeError, but I see your point.(p.s.: i am debating with good intentions, mainly cause i see no counterarguments aside from my own, not trying to start a flamewar)
Well, I do agree that the problem can be solved with better object design from the developer's side. A snippet like this one:
is fairly readable.
However, it depends heavily on a developer having the foresight to design a class like so and the other developers knowing of this design detail.
The other thing to remember is that this proposal is not intended to give JS a new language feature or give developers the ability to do something that they haven't been able to do before, it is just to make the life of the developer a little bit easier and the resulting code a little bit easier to read.
I understand debating with good intentions, I appreciate that. No one here wants to start an actual flamewar :)
How fixed is this syntax? Because while it's in draft and there is still a possibility of changing it: this is quite painful syntax, a keyword that turns an entire statement into a "is allowed to fail due to 'X does not exist' errors" would be so much nicer to work with. For instance,
... if exists [else ...]
would allow for pleasant to read, easy to type expressions such aslet value = ... if exist
andif (... if exists else Number.MAX_VALUE > 2)
. This would be so much better, and would still be guaranteed to not conflict with existing code (sinceif
cannot be followed by anything except(
right now), and can be trivially dealt with by transpilers for targeting legacy systems.While the exact syntax is not written in stone yet (in fact, it's subject of much debate) I'd say it's not fixed at all. However, what you're describing seems to be a different feature that fixes a different problem.
They may have some overlap in the sense that they try to change how we act on null or undefined references, but they both approach it in very different ways.