How to avoid the JavaScript error “cannot read property ___ of undefined” without nesting logical AND (&&)

If we’re working with pulling data from APIs in JavaScript and React we may encounter the error “cannot read property [property name] of undefined. This occurs when we try to read a value from a nested object, but the object’s parent object has returned undefined:

const object = {
    name: 'Omar',
    hobbies: {
        sewing: {
            favorite: true,
        },
        hiking: {
            favorite: false,
            frequency: 'often',
        },
    },
}

console.log(object.hobbies.fishing.frequency) // Throws errror: "TypeError: Cannot read property 'frequency' of undefined"

We are trying to pull data that we think should exist on the object (on our API, etc.), but it doesn’t. Sometimes we don’t want this to stop our program, but instead we want the property of an undefined parent to return “undefined”. This could be so that we could skip the creation of an element for that particular item in a React .map loop, or for some other reason.

One common method to fix such an error is to use a format like the following:

const object = {
    name: 'Omar',
    hobbies: {
        sewing: {
            favorite: true,
        },
        hiking: {
            favorite: false,
            frequency: 'often',
        },
    },
}

const fishingFrequency = object.hobbies && object.hobbies.fishing && object.hobbies.fishing.frequency
console.log(fishingFrequency) // returns undefined 

The above variable fishingFrequency will be set to undefined because the first parent object that doesn’t exist will return undefined, and the logical AND (&&) won’t let us go any further. On the other hand if the property frequency of a fishing object did exist, fishingFrequency would be set to that value, because it would only take the last value of the string of logical AND operators.

The problem with this method is that, as we can see, with nested objects we end up with a long string of && operators and object/property names. To avoid this, we can use a method known as the “Maybe Monad”:

const fishingFrequency = ((object.hobbies || {}).fishing || {}).frequency
console.log(fishingFrequency) // returns undefined 

Using the method above, if an object property is not defined, then the value defaults to an empty object. Since checking a property that does not exist on an object returns undefined, the above solution will always return either a value or undefined!