Optional Chaining
October 24, 2020
A common error in the console I've seen is Error: Cannot read property '<name>' of undefined
where <name>
is a value expected to be other than undefined or null.
Here's an example of a player object that has a collection of Pokemon. Each Pokemon object has at least a name, Pokedex ID, and their pre-evolution name. What some also have is an evolution
property which contains what stone it needs to become this Pokemon from its preEvolution
stage.
const player = {
name: "Dana",
pokemon: [
{
name: "Lucario",
dexId: 448,
preEvolution: "Riolu"
},
{
name: "Roserade",
dexId: 407,
evolution: {
stone: "Shiny"
},
preEvolution: "Roselia"
},
{
name: "Beautifly",
dexId: 267,
preEvolution: "Silcoon"
},
{
name: "Ampharos",
dexId: 181,
preEvolution: "Flaaffy"
},
{
name: "Flareon",
dexId: 136,
evolution: {
stone: "Fire"
},
preEvolution: "Eevee"
},
{
name: "Froslass",
dexId: 478,
evolution: {
stone: "Dawn"
},
preEvolution: "Snorunt"
},
]
}
If I wanted to print all the Pokemon names to the console, I can do:
player.pokemon.forEach(pokemon => console.log(pokemon.name));
But what if I want to print out any evolution stones that the pokemon requires to evolve?
This code would give an error since not all pokemon have one:
player.pokemon.forEach(pokemon => console.log(pokemon.evolution.stone));
// TypeError: Cannot read property 'stone' of undefined
You could do a check by adding an if-statement if the pokemon has an evolution
property:
player.pokemon.forEach(pokemon => {
if(pokemon.evolution !== undefined){
console.log(pokemon.evolution.stone)
}
else {
console.log(undefined);
}
});
// undefined
// "Shiny"
// undefined
// undefined
// "Fire"
// "Dawn"
While this works, there's a shorthand property called "optional chaining" using ?.
to check if the property is undefined or null before continuing with the expression:
player.pokemon.forEach(pokemon => {
console.log(pokemon.evolution?.stone)
});
// undefined
// "Shiny"
// undefined
// undefined
// "Fire"
// "Dawn"
This syntax isn't only used on objects. It can be put after any variable, Array, or Function as a check.
To execute a Function that may not be defined, you can append ()
after the optional chaining to execute it.
If we weren't sure if the player object had a method called possibleFunction
to use, we can check it before executing it.
player.possibleFunction?.()
I find myself using this shorthand approach more often than the usual if-statement to see if a value is undefined or null to avoid an error.
Resources: