For those scenarios, I like to use a little helper like this:
/**
* Accesses nested properties and returns a default value if it encounters null or undefined along the way.
* @param fallback A fallback value if any property or its value is null or undefined.
* @param path The path to access a nested property
*/
export const propOrDefault = <T, R>(fallback: R) => (...path: string[]) => (obj: T | null | undefined): R =>
path.reduce((partialObj, propertyName) => {
if (partialObj && propertyName && partialObj.hasOwnProperty(propertyName)) {
return partialObj[propertyName] || fallback;
}
return fallback;
}, obj);
This is TypeScript, but it should get the point across. And the additional type info might help with understanding.
Example usage:
const isValid = propOrDefault(0)('staff', 'members', 'length')(state) < 5;
As you can see, this helper uses currying so you could pre-configure it for later use like so:
const propOrTen = propOrDefault(0);
const countStaffMembers = propOrTen('staff', 'members', 'length');
const result = countStaffMembers(state);
There are loads of libraries out there with similar tools like lodash and ramda.