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!
Top comments (5)
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.
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.
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.
Yes! This is a solution where you may not be using babel or some other transpiler.
You can now try optional chaining in JSitor online editor to test it out.