Optional chaining is great: it allows us to safely access object properties without worrying if they exist:
const user: {
name: "Bob"
}
const val = user?.pet?.name;
Rather than crashing if pet
doesn't exist on user
, it'll simply return undefined
.
While this is promising, optional chaining is in stage 4 of proposal for the ECMAScript standard, and is therefore not guaranteed to be available unless specifically accommodated in a transpiler you're using.
Rolling Your Own
The good news is we can fairly easily roll our own optional chaining-like function! Let's call it deepGet
:
function deepGet(obj, ...props) {
try {
return props.reduce((acc, el) => acc[el], obj);
} catch (e) {
return undefined;
}
}
We can see that we try to iterate over all props
in our reduce
function. If an error is ever thrown, we just return undefined
! Let's see it in action:
const obj = {
user: {
name: "Joe",
age: 20,
pets: [
{
name: "Daffodil",
type: "dog",
toys: [
{
name: "Toughy",
price: 1999
}
]
}
]
}
};
function deepGet(obj, ...props) {
try {
return props.reduce((acc, el) => acc[el], obj);
} catch (e) {
return undefined;
}
}
console.log(deepGet(obj, "user", "pets", 0, "toys", 0, "price"));
// 1999
console.log(deepGet(obj, "user", "dogs", 0, "toys", 0, "price"));
// undefined
And there you have it, your own safe deepGet
function!