DEV Community

Optional Chaining may be coming to JavaScript

Sammy Israwi on February 20, 2018

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....
Collapse
 
briansotodo profile image
b

I don't know about the syntax (func?.() and arr?.[0] is kind of weird) but it would be really useful!

Collapse
 
sammyisa profile image
Sammy Israwi

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!

Collapse
 
denvercoder profile image
Tim Myers

JS is looking more like Swift every day. 👍

Collapse
 
twof profile image
Alex Reilly

Swift masterrace

Collapse
 
wahabshah23 profile image
Abdul Wahab Shah

Typescript already has this. Would be nice in vanilla Js too

Collapse
 
neoscrib profile image
Tanner Jepsen

Typescript does not have it. They won't implement anything in stage 1. github.com/Microsoft/TypeScript/is...

Collapse
 
evanderwpmorais profile image
Evander

I have used it in Angular isn't it Typescript?

Thread Thread
 
cristianfalcone profile image
Cristian Falcone

That's from Angular template syntax. It's called safe navigation operator. Not from TypeScript.

Collapse
 
sammyisa profile image
Sammy Israwi • Edited

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?

Collapse
 
rapasoft profile image
Pavol Rajzak

It is present in CoffeeScript

Collapse
 
t4rzsan profile image
Jakob Christensen

In C# it is also called the Elvis-operator because it looks a bit like two eyes under curvy hair.

Collapse
 
leebradley profile image
Leopold Bradley

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?

Collapse
 
sammyisa profile image
Sammy Israwi

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.

Collapse
 
buinauskas profile image
Evaldas Buinauskas

Didn't know this exists in c#! Neat

Collapse
 
kjellski profile image
Kjell Otto

C# is awsome, have a look here: docs.microsoft.com/en-us/dotnet/cs...
There is also async await for years now... ;)

Collapse
 
sammyisa profile image
Sammy Israwi

C# is a fantastic language :D

Collapse
 
buinauskas profile image
Evaldas Buinauskas

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 :)

Collapse
 
caubeen profile image
caubeen

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.

Collapse
 
ben profile image
Ben Halpern

Wooo fun!

Collapse
 
blunket profile image
Andrew Siegman

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?

Collapse
 
sammyisa profile image
Sammy Israwi

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.

Collapse
 
blunket profile image
Andrew Siegman

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)

Thread Thread
 
sammyisa profile image
Sammy Israwi • Edited

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 :)

Collapse
 
pomax profile image
Mike Kamermans • Edited

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.

Collapse
 
sammyisa profile image
Sammy Israwi

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.

Collapse
 
metapgmr profile image
Jean-Jacques Dubray

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.

Collapse
 
briankephart profile image
Brian Kephart

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.

Collapse
 
pat_metzdorf profile image
Patrick Metzdorf

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.

Collapse
 
nikolay profile image
Nikolay Kolev • Edited

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

Collapse
 
qm3ster profile image
Mihail Malo • Edited
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.

Collapse
 
villesau profile image
Ville Saukkonen

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

Collapse
 
sammyisa profile image
Sammy Israwi

Oh very interesting! Thank you for developing it!

Collapse
 
qm3ster profile image
Mihail Malo

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

Collapse
 
mladenstojanovic profile image
Mladen Stojanovic

Wow! Can't wait for this one!

Collapse
 
kylessg profile image
Kyle Johnson

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

Collapse
 
anthonybrown profile image
Tony Brown

Me likey

Collapse
 
inf3rno profile image
inf3rno

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

Collapse
 
sammyisa profile image
Sammy Israwi

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.

Collapse
 
inf3rno profile image
inf3rno • Edited

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.

Collapse
 
egoist profile image
EGOIST

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

codepan.net/gist/0e78b867ead5472db...

Collapse
 
irvandoval profile image
Irvin Sandoval • Edited

It will be an amazing and very useful feature 🤓