Author: ICBU Dongmo
Write at the front: welcome to Alibaba ICBU interactive & end technology front end team column, we will share quality front end technology articles with you, welcome to pay attention to & exchange yo!
Optional-chaining is a feature in Javascript that makes lazy evaluation more robust. It was implemented in V8 in March 2019 and turned on as an experimental flag in Chrome some time after that. In this article, all code runs in typescript unless otherwise noted. Before typescript 3.7, TS did not natively support option-chaining operators; In typescript 3.7 released in November 2019, TS supports optional chaining operators as a first-class feature.
Fast processing of a numerical data structure
When processing data, we often encounter situations where we need to read layers of tree data, often in order to obtain a certain level of data. Consider the following data from the back-end API: We need to get the city name of the first primary office from a user record:
const apiResult = {
name: "Neville Bowers",
office: {
primary: {
city: "San Francisco",
state: "CA"
}
}
}
Copy the code
To get the data we want, we write:
const city = apiResult.office.primary.city;
// --> "San Francisco"
Copy the code
However, the underlying premise of this code is that API returns always return a stable structure at run time. In practice, however, we will encounter the absence of the Office field in the user structure in the result returned by the API:
const apiResult = {
name: "Yatharth Agarwal"
}
const city = apiResult.office.primary.city;
// --> Uncaught TypeError: Cannot read property 'primary' of null
Copy the code
Further, if we hadn’t thought to catch an exception, our application might crash! It is clear that we need to be more careful when reading layers of apiResult — something we take for granted in hindsight but can easily overlook when developing, especially if our API returns solid data structures most of the time, or if the relevant API documentation does not give all possible states of the returned data.
Our most conservative approach to this situation is to assume that all the fields at each level of the tree are likely to be non-existent. Let’s explore what specific means are available to deal with possible missing fields.
A/Logic to determine whether layers exist
We can layer by layer to determine whether a field exists to determine the value logic.
let city: string | undefined = undefined; if (apiResult) { const office = apiResult.office; if (office) { const primary = office.primary; if (primary) { city = primary.city; }}}Copy the code
This is certainly an effective way to flex against unexpected apiResult structures at runtime, but the code is too long and unreadable. Some developers would call this code a “death pyramid “. Additionally, this way of writing requires us to let the city to be reassigned, which is a backward step in terms of the code specification.
B/A ternary expression with successive layers
We can safely get the city field using a hierarchical ternary representation:
const city = ! apiResult ? undefined : ! apiResult.office ? undefined : ! apiResult.office.primary ? undefined : apiResult.office.primary.city;Copy the code
This method is a little more concise than the previous one. , and allows us to keep city immutable (using const); But the code is still hard to read and redundant (e.g., undefined appears three times).
C/logical expression
We can also use logical expressions to safely retrieve the city field:
const city =
apiResult &&
apiResult.office &&
apiResult.office.primary &&
apiResult.office.primary.city;
Copy the code
This code is a little more concise than a hierarchical ternary expression. However, it is still lengthy.
D/try/catch block
We can also safely retrieve the city field using a try/catch block:
let city: string | undefined = undefined;
try {
city = apiResult.office.primary.city;
} catch (error) {
// Swallow Error
}
Copy the code
The try/catch approach is the closest thing to a “read directly” approach. But if you do this for values, you’re writing a lot of try/catch blocks in your code, and the city variable has to be reassigned.
E/lodash ramda etc
Some libraries provide secure methods for tree combing. For example, in Lodash, we can safely get the city using the get method:
import * as _ from 'lodash';
const city = _.get(apiResult, 'office.primary.city', undefined);
Copy the code
This scheme is by far the simplest, with code length only slightly longer than “read straight”. However, we paid a development price for this:
- IDE hints at layer by layer values.
- Pair value path
office.primary.city
Compiler type derivation (i.ecity
The type of is indeterminate unless you specify it explicitly.
Optional – Chaining operators
As mentioned above, each scheme for hierarchical value of tree data has its disadvantages. So is there a more perfect solution?
Yes, it is the Optional-Chaining operator
The Optional-Chaining operator is a binary operator that returns undefined if the laining value is null/undefined. > otherwise returns its rvalue
// if `a` is `undefined` or `null`: // return `undefined` // else: // return `a.b` a? .b; // The optional chaining operator is equivalent to: (a == null) ? undefined : a.b;Copy the code
(Above quoted from github.com/tc39/propos…)
In other languages, this operator is often named the Safe Navigation operator, the Existential operator, the Null-Conditional operator, or the Null Propagation Operator.
The Optional Chaining operator can be used in combination to elegantly handle scenarios that require layers of value from the tree: In the consecutively used Optional Chaining operator, if null or undefined is returned anywhere in the middle, the entire chain returns undefined.
To return to our example, if we used the Optional Chaining operator, it would look like this:
const city = apiResult? .office? .primary? .city; // --> string | undefinedCopy the code
You see, this statement is a very straightforward solution to our problem. It is concise, readable, and retains all of the development-time tooltips.
TypeScript didn’t support this feature until 3.7, when TypeScript was waiting for TC39 to confirm whether to include support for Optional Chaining operators as a standard. If you are using TypeScript prior to version 3.7, you can use optional chaining with the ts-optchain package.
❤️ Thank you for seeing the end ~
Alibaba international website (ICBU, Alibaba.com) is the world’s largest cross-border trade and service platform. We have new technical challenges all the time, enough interesting challenges to satisfy all your curiosity and thirst for knowledge, and well-known foreign partners (Google & OpenSky).
If you want to come to ICBU to develop the front end with me, please send your resume to [email protected] and we will respond to your interview arrangement quickly. : -)