loading...

Optional Chaining in JavaScript Right Now!

samholmes profile image Sam Holmes ・2 min read

In case you don't know what Optional Chaining is, it's the ability to safely access properties of a variable without a reference error.

var obj = undefined
obj?.foo // Returns undefined without throwing an error

This is an experimental JavaScript feature proposal, however, we can use a form of this feature today with the help of the a Proxy object!

Let's define a function which will return a special Proxy object which will prevent references on undefined values allowing us to safely query for properties.

function safe(value){
    return new Proxy({}, {
        get: (_, prop) => {
            if (prop === 'unsafe')
                return value
            else if (value && typeof value[prop] !== 'undefined')
                return safe(value[prop])
            else
                return safe(undefined)
        }
    })
}

Now we can use this function as an alternative to the Optional Chaining Operator like so:

var obj1 = undefined
var obj2 = {foo:23}

console.log(safe(obj1).foo.unsafe) // Returns undefined without throwing an error
console.log(safe(obj2).foo.unsafe) // Returns 23
console.log(safe(obj2).foo.bar.baz.unsafe) // Returns undefined

There is a con to this approach in that unsafe becomes a reserved property within the chain. Though, we can implement a second parameter to the safe function to take care of this edge case:

function safe(value, unsafe = 'unsafe'){
    return new Proxy({}, {
        get: (_, prop) => {
            if (prop === unsafe)
                return value
            else if (value && typeof value[prop] !== 'undefined')
                return safe(value[prop])
            else
                return safe(undefined)
        }
    })
}

That's all for now. Let me know in the comments what you think of this pattern.

I've open sourced this idea as an NPM package: safeunsafe

Cheers!

Discussion

pic
Editor guide
Collapse
karataev profile image
Eugene Karataev

This is a clever use of Proxy to safely access object properties ✨

What do you think about lodash way to get object properties? It solves the same problem, but in different way.

var obj = {foo: {bar: 'baz'}};
_.get(obj, 'foo.bar'); // baz
_.get(obj, 'lol.kek'); // undefined
Collapse
samholmes profile image
Sam Holmes Author

This approach is reasonable. It comes down to style really. Using Proxies allows you to tap into some meta-programming aspects of JavaScript where you can change the behavior or the syntax slightly. Either way you accomplish this is fine, however Proxies seems like a nicer use case.

Collapse
jasonbarry profile image
Jason Barry

I'd lean on the @babel/plugin-proposal-optional-ch... plugin instead – seems a bit safer. Although your method is clever and could be a quick way to get optional chaining if you don't currently have a transpilation step.

Collapse
samholmes profile image
Sam Holmes Author

Yes! This is a solution where you may not be using babel or some other transpiler.

Collapse
ashvin777 profile image
Ashvin Kumar Suthar

You can now try optional chaining in JSitor online editor to test it out.