DEV Community

Nabin Adhikari
Nabin Adhikari

Posted on • Updated on

Optional Chaining JavaScript / TypeScript

alt text

While working with JavaScript or Typescript, one of my most dreadful experience is reading property of object since there is no optional chaining (please correct me if I'm wrong). Obviously, we can have multiple if/else statement for safe property extraction, I think there should be a better clean approach.

Then, I started searching for such libraries and they work very well except they were lacking one most important feature (for me) to give fallback value. That is why I started thinking of creating npm module to solve this problem as my first npm module ever so that I could help other developers as well.

Today, I've created safechainjs, which exactly does what I wanted and I am very excited to publish my first ever npm modules. I'd be very honored for any feeback or suggestion here.

It is very easy to get started. For e.g.

$ npm install --save safechainjs
Enter fullscreen mode Exit fullscreen mode

For a object like this:

const obj = {
    name: {
        firstName: "Albert",
        lastName: "Einstein"
    },
    dob: "1897/03/14",
    wife: ['Maric', 'Elsa']
};
Enter fullscreen mode Exit fullscreen mode

We can easily and safely pull out properties using safechainjs like this.

const safechain = require('safechainjs');
const fname = safechain(obj, 'name', 'firstName', 'Unknown'); // Albert
const address = safechain(obj, 'address', 'postcode', 0); // 0
const wives = safechain(obj, 'wife', []); // ['Maric', 'Elsa']
Enter fullscreen mode Exit fullscreen mode

Minimum three parameters are needed for function to sucessfully work.

  • First argument is the object to get property from
  • Multiple arguments to grab property in multiple level
  • Last argument is fallback value to be returned incase of missing request property

I'd really appreciate if you use it and provide any suggestions or feedback.
Happy JS
Nabin Adhikari

Discussion (4)

Collapse
pichardoj profile image
J. Pichardo

Nice post @nabinadhikari , I actually made a post about this a while ago here, it might be of use.

Collapse
nabinadhikari profile image
Nabin Adhikari Author

@pichardoj Ahh, you have a nice approach for this solution. Thank you for pointing to your post, I've learned lot more from your post about optional chaining.

I see a small issue though, what happen if there is "." in property name like {"H.Angel": {"name": "Angel", "location": "Hobart" }}.

This is a normal case in the project I'm currently working on, so I had to take the different approach.

But again, better approach. I couldn't think of it. :)

Collapse
pichardoj profile image
J. Pichardo • Edited

Yeah, that's why I ended using proxies and functions, in order to do something like

optional(obj, obj => obj["H.Angel"].name.location, "Default");
Collapse
pmcgowan profile image
p-mcgowan • Edited

There was a massive issue discussion on the TS repo about the "elvis" operator, or safe null coalescing in js. I don't have the link, but a js implementation went to stage 2 IIRC for this exact thing.

Js needs this, as

x && x.y && x.y.z
or
((x || {}).y || {}).z
are obviously terrible.

You could write a simple function using try catch to do this, or prototype on object as well:

Object.prototype._elvis = function (v) {
      let tmp = this;
      try {
          v.split('.').forEach(i => tmp = tmp[i]);
      } catch (e) {
          return null;
      }
      return tmp;
  }

then

x = { y: { z: 2 } };
x._elvis('y.z');  // => 2
x._elvis('y.z.q.r.t');  // => null

Also note - works for null but not undefined.