Optional Chaining and Nullish Coalescing in TypeScript
Overview
TypeScript is becoming increasingly popular for both frontend and backend web development. TypeScript is designed for large-scale application development and can be transpired to JavaScript. Because TypeScript is a superset of JavaScript, existing JavaScript programs are also valid TypeScript programs. TypeScript may be used to develop JavaScript applications that can run on both the client and server sides.
Introduction
Optional chaining in TypeScript is defined as the ability to quickly cease executing an expression if a portion of it evaluates to null or undefined. The ?. operator was added in TypeScript 3.7.
Optional chaining in typescript is frequently used in conjunction with nullish coalescing, which is the ability to revert to a default value when the primary expression evaluates to null or undefined. The operator to apply in this circumstance is ?
In this tutorial, we'll look at typescript optional chaining and nullish coalescing.
Optional Chaining
Optional chaining in TypeScript is the process of querying and invoking properties, subscripts, and methods on optional that may be nil. The ECMAScript feature allows developers to stop expressions from running if they find undefined or null values.
TypeScript, being a superset of JavaScript, provides IDE support and minimum configuration while benefiting from JavaScript resources. The most recent TypeScript version includes two new features: typescript optional chaining and nullish coalescing in typescript operators.
Optional chaining in TypeScript is a fundamental feature that includes authoring code in which the script stops execution if a user encounters undefined or null. For optional property access, the operator ?. is used. Let us investigate typescript Optional chaining, its syntax, and its implementation.
Now let's see the syntax for typescript optional chaining
Syntax :
The syntax for optional chaining in TypeScript is as follows.
Before diving into a new operator, let's have a look at the code before replacing it with ?
This new operator ?. differs from && checks in that optional chaining in typescript regards valid data as 0 or truthy as empty.
In this article, I'll go through the three optional chaining operators listed below and explain why we would wish to utilize them in our TypeScript or JavaScript code :
- ?.
- ?.[]
- ?.()
Motivation
Let's start with a real-world illustration of how typescript optional chaining in typescript might be useful. I've written a details function that accepts any value and serializes details as json. I'm sending the method a user object with two properties :
Output :
Assume we wish to allow function callers to define the indentation level. We'll define an Options type and add a details function options argument. The indentation level will be retrieved from the options. formatting.indent property :
When invoking details like this, we may now provide a two-space indentation level :
The resultant JSON is now indented with two spaces and spread across numerous lines, as expected :
Typescript Optional Chaining parameters, such as the one we presented above, are common. Callers to the function may, but are not needed to, supply an options object.
Let us modify our function signature to make the options argument optional by attaching a question mark to the parameter name :
Assuming we have the —strictNullChecks compiler option set in our TypeScript project (part of the —strict family), TypeScript should indicate the following type error in our options.formatting.indent expression :
The object is possible 'undefined'.
Because the options argument is optional, it may have the value undefined. Before accessing options, We should first check whether options hold the value undefined before accessing options.formatting Otherwise, we risk obtaining an error at runtime :
We could alternatively use a little more generic null check that checks for both null and undefined — notice that we're using != rather than !== in this case :
The type error is no longer present. We may invoke the details method and send details an options object with specified indentation :
Alternatively, we may use details without supplying an options object, in which case the indent variable will be set to undefined and JSON.stringify will use a zero indentation level :
Both of the above function calls are type-safe. But what if we also wanted to be able to refer to our details function in this manner ?
This is yet another typical pattern. Options objects usually define some or all of their attributes as optional so that function callers can provide as many (or as few) options as they require. To accommodate this pattern, we must make the formatting property in our Options type optional :
Take note of the question mark after the name of the formatting attribute. Although the details(user, ) call is now type-correct, TypeScript displays another type error when attempting to use options.formatting.indent :
The object is possible 'undefined'.
Given the possibilities, we'll need to add another null check here. The value undefined can now be used in formatting :
This code is now type-correct and uses the options.formatting.indent property securely. However, these nested null checks are becoming cumbersome, so let's see how we can reduce this property accessing using the optional chaining operator.
Now we just Completed typescript optional chaining let's see some Operator.
The ?. Operator: Dot Notation
To access options, we may utilize the ?. operator. formatting. at each level of this property chain, indent with checks for null values :
Optional chaining in typescript is described in the ECMAScript standard as follows :
Optional chaining in typescript is a property access and function invocation operator that is disabled if the value to access/invoke is null.
The options ?. formatting ?. indent expression is evaluated by the JavaScript runtime as follows :
Produce the value undefined if options have the value null or undefined.
Otherwise, if options.formatting is null or undefined, output the value undefined.
Produce the value of options.formatting.indent otherwise.
When the?. operator finishes descending into a property chain, it always returns the value undefined, even if it meets the value null. TypeScript's type system emulates this behavior. TypeScript infers that the indent local variable in the following example is of type number | undefined :
Because of optional chaining, this code is much more concise and type-safe than previously. After that, proceed to ?.[] The operator.
The ?.[] Operator: Bracket Notation
Next, consider the ?.[] operator, another member of the optional chaining in the typescript family.
Assume that instead of indent, our indent field on the Options type was named indent-level. To declare a property with a hyphen in its name, we'll need to use quotes :
When invoking the details method, we could now specify a value for the indent-level parameter like this :
The following attempt to access the indent-level property through optional chaining in typescript, however, produces a syntax error :
We can't use the ?. operator followed by a string literal directly Because it would be incorrect syntax. Instead, we may use bracket notation for optional chaining in typescript and the ?.[] operator to retrieve the indent-level property :
Here is our full details function :
Aside from the added square brackets for the last property access, it's pretty much the same as previously.
The ?.() Operator: Method Calls
?.() is the optional chaining family's third and final operator. We may use the ?.() operator to call a method that may or may not exist.
Let's switch back to the Options type to observe when this operator comes in handy. The indent property (typed as a number) will be replaced by a require_Indent property (typed as a parameterless function returning a number) :
We may call our details function and provide a two-level indentation as follows :
We can use the ?.() operator to conditionally activate the require_Indent method if (and only if) it is defined within our details function to determine the indentation level :
If the require_Indent method is not defined, no attempt will be made to invoke it. The entire property chain will evaluate to undefined in that case, avoiding the infamous "require_Indent is not a function" error.
Here are our complete details function once again :
Compiling Optional Chaining to Older JavaScript
After we've seen how the optional chaining operators operate and how they're type-checked, let's look at the generated JavaScript produced by the TypeScript compiler when targeting earlier JavaScript versions.
The TypeScript compiler will generate the following JavaScript code, with whitespace modified for readability :
The assignment to the result variable contains a lot of activity. Let's simplify the code one step at a time. To begin, we'll change the names of the local variables x and y to formatting and require_result, respectively :
Let's move on to the void 0 expression. The void operator always returns the value undefined, regardless of the value to which Void is applied. We can directly replace the void 0 expression with the value undefined :
The structure of the code is much more precise now. You can see that TypeScript is producing the null checks that we would have written ourselves if the optional chaining operators had not been available.
Null and Undefined in the Type System
To represent the values null and undefined, TypeScript's type system offers two highly specific types, null and undefined. TypeScript's type checker, on the other hand, regards null and undefined as permissible values for any type by default. For example, we may assign null to a string value :
When the strictNullChecks option is enabled, null and undefined types are taken into consideration during type checks. The snippet above will no longer type check, and we will obtain the following error message : "Type null is not assignable to type string".
To match the semantics of JavaScript, the types null and undefined are processed differently : string | null is not the same as string | undefined, which is not the same as string | null | undefined. For example, the following expression will not type check and will result in the error message "Type undefined is not assignable to type string | null."
Explicit Checking for Null and Undefined
TypeScript did not have any operators to assist us to deal with null or undefined values until version 3.7. As a result, we had to implement explicit checks before accessing a variable that may assume them :
We begin by declaring a new type, Undefined_String, which represents a string that might be null or undefined. Then, if the string supplied as an argument is defined, we build a function that returns the string "casual" otherwise.
This method works well, however, it results in complicated code. Furthermore, concatenating calls where distinct sections of the call chain may be null or undefined is difficult :
In the above example, we defined the class Person using the previously described type Undefined_String. Then we wrote a function that returned the person's complete name in uppercase. We must constantly verify the real value since the field we access may be null or undefined. Person::Uppercase_Name(), for example, returns undefined if the whole name is not specified.
This method of implementation is time-consuming and difficult to read and maintain. As a result, TypeScript has included optional chaining and nullish coalescing in typescript version 3.7.
Optional Chaining in Typescript
The ?. operator, as we saw in the introduction, is at the heart of optional chaining, allowing us to halt running expressions when the runtime encounters a null or undefined value. In this part, we'll look at three different applications for such an operator.
Optional Property Access and Optional Call
We can rewrite Person::Uppercase_Name() lot more simply using ?. operator :
Person::Uppercase_Name() is now implemented as a one-liner. This.Name.toUpperCase() will be calculated if this.Name is specified. Otherwise, like previously, undefined will be returned.
However, the initial use of ?. may produce a null or undefined expression. As a result, the optional property access operator can be chained as follows :
In the above example, we first generated an array, people, which included two objects of type Person. Then, using Array::find(), we look for someone with the uppercase name of anyone else. We must account for this when reporting the length of the name since Array.find() returns undefined if no entry in the array fulfills the condition. We achieved this in the example by chaining ?. calls.
Furthermore, the optional call r?.Uppercase_Name() reflects the second usage of? We can conditionally call expressions if they are not null or undefined in this manner.
We'd have to use a more elaborate if statement if we didn't utilize ?. :
Nonetheless, there is a significant distinction between the if and the chain of ?. calls. The former is closed, but the latter is not. This is done on purpose since the new operator does not short-circuit on valid data like 0 or empty strings.
Optional Element Access
The last application of ?. is optional element access, which allows us to access non-identifier attributes if they are defined :
Output :
In the preceding example, we developed a function that returns the first member of a list (assuming the list is represented as an array) if defined, else undefined. The question mark following the name of the list indicates that it is an optional parameter. As a result, its type is T[] | undefined.
The two head calls will print 1 and undefined, respectively.
A Note on short-circuiting
When optional chaining in typescript is used in longer phrases, the short-circuiting it provides is limited to the three scenarios discussed above :
The above example provides a function that computes the percentage of a numeric field. However, because sample ?.bar may be undefined, we may wind up dividing undefined by 100. Because of this, the expression above does not type check when strictNullChecks is enabled : "Object is possibly undefined".
Nullish Coalescing in TypeScript
Nullish coalescing in typescript allows us to declare a kind of default value that will be used in place of another expression that evaluates to null or undefined. Let x = sample?? bar(), strictly speaking is the same as let x = sample!== null && sample!== undefined? bar(), sample : We can rebuild Person::NameLength() using it, as well as optional property access, as follows :
This new version is much easier to read than the previous one. ??, like ?., only works with null and undefined values. As a result, if this.Name was an empty string, the returned value would be 0 rather than -1.
Conclusion
- We've seen what Optional chaining in TypeScript is and how it works.
- It uses the operator (?.) to determine whether or not values are present. It replaces lines of code that were previously used to check the presence of the arguments.
- We've also seen a few examples that are simple to grasp and demonstrate the kind of faults that may occur during Optional chaining.
- In addition, the ?. operator can be applied to function arguments.
- We showed how to utilize Optional Chaining and nullish coalescing in typescript together to produce easy and legible code without having to deal with endless conditionals.
- We also compared them to TypeScript 3.6 code, which is significantly more verbose.
- In any case, strictNullChecks should always be enabled. By default, such a flag includes a variety of extra-type tests, which help us build sounder and safer code.