Safely Access Nested Object Properties with Optional Chaining

JavaScript's optional chaining operator was introduced as part of ES2020.

This operator allows developers to access deeply nested properties within objects while automatically handling any edge cases where a property may be undefined or null.

Consider an object called movie:


const movie = {
title: "Oppenheimer",
director: {
name: "Christopher Nolan",
birthYear: 1970,
},
};

It has a title, Oppenheimer, a director property, which is a nested object, and a director has a name and a birthYear.

In order to access birthYear, we could do movie.director.birthYear if we knew it was there:


const birthYear = movie.director.birthYear;
// Output: 1970

However, let's suppose that we're working with some data where we're not exactly sure of the shape. In the real world, our data often is missing or incomplete or structured incorrectly.

For example, let's say that for some reason Director has a capital 'D', or it's just missing entirely.

Here we have a different movie, this time it's Barbie, and we assume that all movies have information about the director.


const movie = {
title: "Barbie",
};
const birthYear = movie.director.birthYear;
// Output: Uncaught TypeError: Cannot read properties of undefined (reading 'birthYear')

In this case, when we try to access the birthYear property, we get an error.

If we were to manually check for the existence of the birthYear property, we could do something like this:


const birthYear = movie && movie.director && movie.director.birthYear;

However, this is pretty long and clunky.

The Optional Chaining Operator ?.

To handle this more smoothly, we can use the optional chaining operator ?..

Extracting the birthYear only if the director exists would look like this:


const birthYear = movie?.director?.birthYear;

This code checks if movie, movie.director, and movie.director.birthYear all exist.

The optional chaining operator (?.) checks if the preceding value is null or undefined. If it is, the entire expression short-circuits, returning undefined.

For example, if the movie did not have a director at all, the expression would return undefined.

Optional Chaining with Functions

The optional chaining operator can also be used when calling a function or method that may or may not exist.

Like before, you can use it by adding a question mark after the property name, followed by parentheses:


const movie = {
director: {
birthYear: 1970,
},
getMovieData: () => "aksjdlkasjdlkas"
};
movie.getMovieData?.();

In this case, the movieData will give us the result of calling the getMovieData function if it exists.

If movie or movie.getMovieData are null or undefined, the whole expression short-circuits, and movieData will be undefined.

Optional Chaining with Arrays

Say the movie has a property called actors with an array of actors:


const movie = {
// properties as before
actors: ['RDJ', 'Cillian Murphy']
}

If we wanted to get the second element out of actors, we could do something like this:


movie.actors[1]

However, if we're not sure whether actors exists or not, we can use optional chaining to avoid errors by adding the ? after actors:


movie.actors[1] // Output: Cillian Murphy
movie.actors?.[1] // Output: Cillian Murphy
movie?.actors?.[1] // Output: Cillian Murphy

Now, if we misspell actors, the optional chaining will prevent an error:


console.log(movie.actrs?[1]); // Output: undefined

Wrap Up

Optional chaining in JavaScript is a useful syntactic sugar that allows us to tentatively try and access properties off of objects that may or may not exist, making our code more safe and easier to read than handling edge cases manually.

Transcript

00:00 JavaScript's optional chaining operator, which was introduced as part of ES 2020, allows developers to access deeply nested properties within objects while automatically handling any edge cases where a property may be undefined or null. So I have a very simple object

00:16 here called movie. It has a title, Oppenheimer, a director property, which is a nested object, and a director has a name and a birth year. So of course, in order to access birth year, if I knew for sure that it was in there, nested under director, I could do movie.director.birth

00:33 year. But let's suppose that I'm working with some data where I'm not exactly sure of the shape. It's kind of silly when I have to find it right here for you, but in the real world, our data often is missing or incomplete or structured incorrectly. If I run this line,

00:48 movie.director.birth year, we definitely get the correct answer, 1970. But let's say that for some reason, director has a capital D, or it's just missing entirely, right? We have a different movie. This time it's Barbie. And we assume that all movies have information about the director.

01:07 But in this case, if I copy this and run it, we get an error, right? We get a type error. Cannot read properties of undefined because director is undefined. We can't do something like undefined.birth year. That generates a type error. So in the past, without the optional

01:25 chaining operator, the way we would do this safely, if we wanted to extract birth year, only if director exists, would look something like this. This is one option, at least. Movie and and movie.director and and movie.director.birth year.

01:44 And then I could save this to a variable. I'll call it year. And if we look at year, it's going to be undefined, but there's no error involved. This is totally valid. We're just using some basic Boolean logic. So if movie.director doesn't exist, like it doesn't here, right? This

02:00 whole thing is now going to be false. And we'll end up with undefined as the return value that is stored in year. So this is kind of the old way of doing it. Now, to be clear, this right here does not protect against, let's do something that doesn't exist, like movie with a B. We'll still

02:16 get a reference error here, because JavaScript doesn't know what this is referencing. So this is a pretty long and clunky way to safely access birth year. Enter the newish optional chaining operator, which is written with a question mark, followed by a period. So I could rewrite this line

02:33 that you see here. I'll comment it out to look like this. Movie question mark, followed by a question mark, dot, director, question mark, and then dot, birth year. Let me expand this so you

02:51 can see it on one line. The question mark dot is going to check to see if the preceding value is null or undefined. And if it is, the entire expression, short circuits, returning undefined. So in this case, movie has a title, and movie is defined, so this is fine. But then we get to dot

03:09 director. Well, there is no director property, right? That evaluates to undefined, which will short circuit the whole thing, and year will be undefined. As you can see over here, it's set to undefined. Just like what we had here, but this is much shorter and much more intuitive. The question

03:24 mark makes a lot of sense as a choice, right? We're questioning, is there director here? If so, let's get birth year. And again, if at any point, movie or movie dot director are null or undefined, the whole thing short circuits, and we end up with undefined. But if I restore this to have a

03:42 director, I don't know Greta Gerwig's birth year, so I'm going to go back to Oppenheimer. And his birth year, Christopher Nolan, make sure I spell it correctly, was 1970. If I rerun this,

03:58 now year is in fact set to 1970, because this evaluated not to be null or undefined. This evaluated not to be null or undefined, and then we access birth year, and that's going to give us 1970. We can also use the optional chaining operator when calling a

04:13 function or method that may or may not exist. So I'll add a simple function in here called, I don't know, get movie data, and it will just return some nonsense. Okay, so if I want to call

04:28 it, I could do movie dot get movie data, and just assume that it's always there. But of course, if it's not there, and then try and execute that as a function, I get a type error, right? That doesn't exist, undefined, it's not a function. So what I can do is put a question mark, and then a

04:44 dot, and then follow it with the parentheses. So movie dot get movie data, does that exist? Is that thing not undefined and not null? If so, we'll try and execute it. If it is undefined or

04:58 null, then don't execute it. So in this case, it works. I mean, why don't I console dot log, so you can just see that it does work. And we get our console dot log printing out. But if it doesn't exist, or it's misspelled, we don't get an error. And the same is true of working with

05:18 arrays. So if I have an array in here called, I don't know, actors. And, oh gosh, who is in this movie? Robert Downey Jr. is in Oppenheimer. I'll just do rdj. What's his name? Killian Murphy. Let's just leave it at that. I don't know if I spelled his name correctly. Okay, if I want to

05:38 access the second element out of actors, if I just assume that it exists, it would be something like this, right? Movie dot actors, and we get Killian Murphy. But if I'm not sure, movie dot actors exists, same exact syntax, question mark dot. And then if it does exist, it's not null, and it's not

05:57 undefined, we'll access the first element out of the array. But if I misspell it, or it's not on my data, I'll instead end up with undefined instead of an error, which is what I get here. So optional chaining is super useful. It's a nice little piece of syntactical enhancement to JavaScript,

06:16 or sugar. We use a question mark followed by a dot to tentatively try and access a property off of an object that may or may not exist. And it can simplify our code significantly. And remember that if at any point the value before question mark dot evaluates to null or undefined,

06:34 the whole expression will short circuit and return undefined.

More Tips