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 pathoffice.primary.cityCompiler type derivation (i.ecityThe 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. : -)