Safe Navigation With Lodash's get() Function
The _.get() function in Lodash lets you
get deeply nested properties in an object without worrying about whether an
intermediate property is null or undefined. For example, suppose you have
the below object:
const landmark = {
name: 'Golden Gate Bridge',
// GeoJSON feature: https://geojson.org/
location: {
type: 'Feature',
properties: {
city: 'San Francisco',
state: 'California'
},
geometry: {
type: 'Point',
coordinates: [-122.4804438, 37.8199328]
}
}
};
To get the location.geometry.type property, you could use landmark.location.geometry.type. But if landmark.location is undefined,
you would get the below error.
TypeError: Cannot read property 'geometry' of undefined
The _.get() function lets you safely access the nested location.geometry.type property, without having to explicity check whether landmark, landmark.location, or landmark.location.geometry is undefined.
let type = _.get(landmark, 'location.geometry.type'); // 'Point'
delete landmark.location;
// `_.get()` doesn't error out, even though `landmark.location` is
// undefined.
type = _.get(landmark, 'location.geometry.type'); // undefined
// Even if `landmark` is `null`, `_.get()` does not error out.
type = _.get(null, 'location.geometry.type'); // undefined
Default Values
The third argument to _.get() is the default value. If you pass a default value, _.get() will return the default value where it would normally return undefined.
landmark.location.geometry.type = undefined;
// If the value of the property is `undefined`, `_.get()` will return
// the default value.
let type = _.get(landmark, 'location.geometry.type', 'default'); // 'default'
delete landmark.location;
// If the property doesn't exist, `_.get()` will also return the default
// value.
type = _.get(landmark, 'location.geometry.type', 'default'); // 'default'
null vs undefined
Be careful, the _.get() function can return null, even if you specify a default value.
landmark.location.geometry.type = null;
// If the value of the property is `null`, `_.get()` will **not** use
// the default value
let type = _.get(landmark, 'location.geometry.type', 'default'); // null
If you want to make sure _.get() never resolves to a nullish value, you need
to explicitly check the return value using the conditional operator ?.
landmark.location.geometry.type = null;
const checkDefault = (v, def) => v == null ? def : v;
// 'default'
let type = checkDefault(_.get(landmark, 'location.geometry.type'), 'default');