1

I came across this C# like code in a React project. I couldn't confirm if this syntax correct or not. I didn't find any recent ES version release to support this syntax. In current scenario I'm not authorized to execute and check this code.

I tried testing this syntax in browse console and encountered error:

{cart?.widgets?.items.map(widget => (
        <div className="billing-details__box" key={widget.id}>
          <p className="m-0">{widget.name}</p>
          <p className="my-0">{widget.value} $</p>
        </div>
 ))}

My concern with above code is whether cart?.widgets?.items will raise any error or not.

sdgluck
  • 24,894
  • 8
  • 75
  • 90
Viraj Singh
  • 1,951
  • 1
  • 17
  • 27
  • 3
    [Optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining) – Heretic Monkey Feb 17 '20 at 14:25
  • Does this answer your question? [Does Typescript support the ?. operator? (And, what's it called?)](https://stackoverflow.com/questions/15260732/does-typescript-support-the-operator-and-whats-it-called) – rrd Feb 17 '20 at 14:29
  • this code is inside a javascript file. – Viraj Singh Feb 17 '20 at 14:31
  • How can you possibly be expected to modify code that you can't execute? – Jared Smith Feb 17 '20 at 14:33

5 Answers5

2

It is optional chaining which is JS new feature.

Basically it is the same as:

{cart && cart.widgets && cart.widgets.items.map(widget => (
        <div className="billing-details__box" key={widget.id}>
          <p className="m-0">{widget.name}</p>
          <p className="my-0">{widget.value} $</p>
        </div>
 ))}

For more details be sure to visit V8 guide.

2

I couldn't confirm if this syntax correct or not.

It is correct TypeScript code, and is correct JavaScript depending on what engine you're running it in. Chrome (V8) supports this syntax already (see caniuse.com).

Here you can read more about the proposal to add this syntax to a future JS spec.

What is it?

This syntax is called the optional chaining operator, and it allows you to access properties that may or may not exist on an object without having to check for the properties existence no matter how deep the property access expression is.

For example, say we have some object like so:

const user = {
  details: {
    name: "SpongeBob SquarePants"
  },
  repo: null
};

And we want to get their name and, if it exists, some property user.repo.url. We can use the optional chaining operator to get both without having to worry whether repo is an object or not:

console.log(user.details.name) //=> "SpongeBob SquarePants"
console.log(user.repo.url) //=> undefined

It also works for function calls. For example, say when user.repo has a value we know it will be a function that returns a string. However, sometimes, as above, it may not be a function. We can do the following to call the function if it exists, but the code will not throw an error if the value at user.repo.url is not a function:

console.log(user.repo?.url()) //=> undefined

Without optional chaining operator?

You can achieve the similar behaviour to the optional chaining operator by explicitly checking the truthiness of each object property in the chain of properties that you are accessing.

This can be done either by taking advantage of JavaScript's short-circuit evaluation behaviour, or more obviously with the ternary operator.

It would look something like this:

function getItems_shortCircuit(obj) {
  return obj && obj.widgets && obj.widgets.items
}

function getItems_ternary(obj) {
  return obj 
    ? obj.widgets 
      ? obj.widgets.items 
        ? obj.widgets.items 
        : null 
      : null
    : null
}

let cart = {
  widgets: null
}

console.log(getItems_shortCircuit(cart)) //=> null

cart.widgets = {
  items: ["a", "b"]
}

console.log(getItems_ternary(cart)) //=> ["a", "b"]

My concern with above code is whether cart?.widgets?.items will raise any error or not.

It depends on whether the project is using TypeScript, which supports optional chaining (?.) out-of-the-box. You can read about it in the TypeScript documentation.

If you are not using TypeScript then you must compile your application using some ESNext compiler such as Babel, which has the @babel/plugin-proposal-optional-chaining plugin.

sdgluck
  • 24,894
  • 8
  • 75
  • 90
  • 1
    You're a little wrong, optional chaining is actually correct JavaScript already and is live in Chrome 80+ (which is the default release currently) and Firefox 74+ (which is currently the dev release) right now. You will still need to transpile if you are targeting other browsers though. https://caniuse.com/#search=optional%20chaining – Stephen M Irving Feb 17 '20 at 14:41
  • 1
    Yeah, I was really happy to see it go live in Chrome at the start of the month. Great answer! – Stephen M Irving Feb 17 '20 at 14:44
  • I guess for other browsers, babel will transpile this code to supported javascript code – Viraj Singh Feb 17 '20 at 14:45
  • @VirajSingh That is correct - so long as you use the plugin linked in the answer, you can use this syntax everywhere once it has been compiled by Babel. – sdgluck Feb 17 '20 at 14:46
  • 1
    In case you didn't know, [nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator) `??` is live in Chome 80+ and regular Firefox (72+) now as well! Now we just need Safari and Edge to get with the program! – Stephen M Irving Feb 17 '20 at 14:47
1

It will be compiled by Babel and it will work. https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining

Andrey
  • 76
  • 2
0

It's Optional Chaining and it should not cause any error if you use polyfills. "?." - is not supported by default yet

Max
  • 582
  • 1
  • 4
  • 13
  • It is supported in Chrome (80+) and Firefox Developer Edition (74+) as of this month! https://caniuse.com/#search=optional%20chaining – Stephen M Irving Feb 17 '20 at 14:50
0

That is probably the optional chaining from Typescript.

Murat Karagöz
  • 35,401
  • 16
  • 78
  • 107