Use the Optional Chaining Operator in TypeScript

Marius Schulz
InstructorMarius Schulz

Share this video with your friends

Send Tweet
Published a year ago
Updated a year ago

This lesson introduces the ?. operator which is known as optional chaining. We're going to look at how we can use ?. to safely descend into an object with properties which potentially hold the values null or undefined. We're also going to learn how to access properties with an expression using the ?.[] bracket notation and how to call functions which may not exist using the ?.() syntax.

Instructor: [0:00] For this example, I've prepared a function called serializeJSON(). It accepts a value of type any, and it parses that value to the JSON.stringify() method. Below, I'm defining a user object with two properties. I'm parsing that to serializeJSON(). Then I'm logging the JSON to the console.

[0:20] Before we move on, let's give this a quick run. I'm going to pull up my terminal. First up, I'm going to compile this TypeScript project. Once that's done, I'm going to execute the resulting JavaScript file in Node. As we can see, the output of our program is the JSON serialized user object without any kind of indentation.

[0:42] Let's now say that we wanted to let the caller of the serializeJSON() method control the formatting by specifying an indentation level. I'm going to create an object type called serializationOptions. I'm going to add to that a property called formatting, and nested underneath that, a property called indent.

[1:01] We can now add an options parameter using that type to our serialized JSON function. Within the function, let's pull out the indent value by saying, options.formatting.indent. Let's parse that through to the JSON.stringify() method. Finally, let's come down to the call side and let's parse some formatting options.

[1:25] Before we move on, I want to make sure that this works. Let's pull up the terminal. Let's run our program again. Indeed, now we get a JSON object that's been indented with two spaces. Let's say that we wanted to make this options object optional, so that the call site could also look like this.

[1:46] We can make the options parameter optional by appending a question mark to the parameter name. TypeScript is now giving us the type error. It's telling us that this object is possibly undefined. This is a valuable warning from the type system. The options parameter can hold the value undefined. Accessing options.formatting can blow up at runtime.

[2:08] Notice that in order to get this type error, you have to have enabled the strict null checks compiler option. In my TSConfig file, I've enabled the strict option, which enables strict null checks and a bunch of other strictness related options.

[2:23] If for some reason you don't want to use the strict option or you can't, the key option to enable is strict null checks. I would encourage you to try and use strict whenever possible. How do we work around this type error? Options can hold the value undefined. Before we access options.formatting, we have to check whether we have a true V Value. If we don't, we can fall back to the value undefined.

[2:52] Let's also say that the formatting property itself is optional. This means that at our call site, we can specify an empty object, and we don't need to specify the formatting property. Now, we get another type error. This time, options.formatting is possibly undefined. We need to do what we did before.

[3:12] We need to first check whether options.formatting is a true V Value. If it isn't, we want to fall back to the value undefined. You can already see that this is getting quite verbose. We've had to add two checks to make sure that options does not hold the value undefined, and that options.formatting does not hold the value undefined.

[3:33] Instead of using these nested conditionals, we can use the optional chaining operator, which is written as a question mark and a dot. The optional chaining operator lets us safely descend into our object all the way down to the indent property.

[3:49] If anywhere in this property chain the object that we want to descend into is null or undefined, we stop descending, and the optional chaining operator produces the value undefined. This is why TypeScript is inferring the union type number or undefined for our local variable.

[4:08] Now that we have the optional chaining operator in place, let's go ahead and let's give our program another run. We can see that we get the unformatted JSON object if we're not specifying the formatting object. If we come in here, we explicitly set an indentation level, and we run this one more time, we can see that we get the formatted JSON object.

[4:30] The optional chaining operator comes in different forms. The one we've seen right now it's the one that's written question mark dot. There's another form that we need when we don't have a simple identifier like we have here.

[4:45] If I were to rename this property to something like, say, indent-level with a hyphen in it, we now get a syntax error in line eight. The quoted property syntax is valid in the type declaration, and it's valid in the object literal down here. It's not valid in this property chain.

[5:03] We can still use optional chaining here if we use the index notation. I would generally recommend to stay away from property names like these, because they're awkward to work with in JavaScript.

[5:15] Sometimes you might have a good reason to use a property name like that, or you might not have control over the property name at all. In these cases, you can use the index notation. The value between the brackets can be any arbitrary JavaScript expression by the way.

[5:29] If you were to work with arrays, you can use the syntax to access array indices, for example. Finally, there's a third version of the optional chaining syntax. That's used for working with functions. To demonstrate the syntax, let me refactor our property to a method. Let's make sure this method is optional.

[5:55] We can now call this function in our optional property chain by stating the name and then the syntax question mark dot, and parentheses for calling the function. Now this syntax might look funky to you initially, but you are going to get used to it.

[6:10] Just keep in mind that whenever you're using optional chaining, the operator always begins with a question mark and a dot. It can be followed by square brackets, or by parentheses. Notice that if we leave out the question mark dot, TypeScript gives us another type error, because it's saying that we cannot invoke an object which is possibly undefined.

[6:33] Let's give this one final run. Indeed, our code still works. Lastly, I would encourage you to have a look at the JavaScript code that TypeScript has generated for us. It's a great way to understand the optional chaining operators in detail. You can see exactly which null checks are being run.

[6:54] You can also see that all properties are evaluated exactly once, and the result is stored in temporary variables. If I renamed the temporary variables to _formatting and underscore _getIndent(), you can see that this code is looking similar to what we had initially before we started using optional chaining.

BTT
BTT
~ a year ago

How can I configure VS code to change all the occurrences, like how it got changed with _a and _b?

Marius Schulz
Marius Schulzinstructor
~ a year ago

@BTT: You can use the “Rename Symbol” command from the command palette in VS Code (see https://code.visualstudio.com/docs/editor/refactoring#_rename-symbol) to rename a variable, function, or other symbol. I use this command quite frequently which is why I’ve assigned it the shortcut ⌘+R.