loading...

Optional Chaining may be coming to JavaScript

sammyisa profile image Sammy Israwi Updated on ・2 min read

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:

TypeError error message

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! ❤️

Posted on by:

sammyisa profile

Sammy Israwi

@sammyisa

Software Developer who works mostly on Web stuff. I like JS, but I also like other things. I also do photography, and look at sneakers online that I will never be able to buy.

Discussion

markdown guide
 

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. 👍

 
 

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?

 
 

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.

 
 

This seems like a useless way to silence errors to me. (specimen?.arms?.length > 2) will return false if specimen is undefined, if arms is undefined, if arms happens to be a boolean for some reason, or if specimen.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 or arms because you would have to handle those scenarios differently. Say, notifying the user that they need to have a specimen 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:

if(user && user.details && user.details.dateOfBirth && user.details.dateOfBirth.month === Month.March)
  console.log("You were born in March");

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:

if(user.isBornInMarch)
  console.log("You were born in March!");

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 as let value = ... if exist and if (... if exists else Number.MAX_VALUE > 2). This would be so much better, and would still be guaranteed to not conflict with existing code (since if 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.

 

You can achieve a similar result with simple functions like:

const O = (val, value = {}) => val && (typeof val === 'object') ? val : value
const A = (val, value = []) => val && Array.isArray(val) ? val : value
const S = (val, value = '') => val && (typeof val === 'string') ? val : value
const N = (val, value = 0) => isNaN(val) ? value : val
const NZ = (val, value = 1) => val === 0 || isNaN(val) ? value === 0 ? 1 : value : val
const F = (f, f0 = () => null) => f ? f : f0

const a = {}

console.log(O(a.b))             // {}
console.log(A(O(a.b).c))        // []
console.log(NZ(a))              // 1 (non-zero number)
console.log(N(a))               // 0 (number)
console.log(S(a, 'hello'))      // hello
console.log(F(a.b)(123))        // null

It's not much more overhead and it works today.

 

The syntax really needs to change, though.

Something like

foo.?bar?[baz] or foo.bar?[baz]? (i.e. question mark right before or after the property that may be undefined)

would be much more intuitive imho.

 

Nice. I've just started using similar methods in Ruby to make my code cleaner, so it will be nice to use this pattern in JS too.

 

Yuck! I can't stand ?.() and ?.[]. Although I understand that the operator is ?., they should've made the ?() and ?[] sugars work, too!

 
const a = b ? c?[0] : d?(1) : "small potatoes"

What do you see?

  • If b then safe access to c[0], else if d then 1 else "small potatoes" or
  • If b then if c an array [0] else safe call to d(1), else "small potatoes"?

Me too.

 

This has got to be the biggest syntactical pain point in JS - would love to see this

 

Now there is a simple tool to migrate your existing codebase to use optional chaining: github.com/villesau/optional-chain... :)

 

Oh very interesting! Thank you for developing it!

 

I think the syntax is excellent. I hope they don't change it.

 
 

Here's also an online playground that supports this feature 😄

codepan.net/gist/0e78b867ead5472db...

 

Great work on worsening readability of js code day by day. :S

 

Why do you think so? I agree that the syntax right now is not great, and that it needs some tweaking. But overall it seems like a nice Quality Of Life improvement on the language.

 

You might be right. I just watch it from a different perspective than you. I would write if(specimen instanceof Alien) where you write if(specimen && specimen.arms && specimen.arms.length > 2). But I can accept that many devs are working with structured code, so this new feature will be fine for them. I might use it rarely too by processing nested config objects.

 
 

It will be an amazing and very useful feature 🤓