Advanced TypeScript Programming Projects
上QQ阅读APP看书,第一时间看更新

Deconstructing objects with REST properties

Where we used spread operators to build up an object, we can also deconstruct objects with something called a REST property. Deconstructing simply means that we are going to take a complex thing and break it down into simpler ones. In other words, destructuring happens when we assign the elements inside an array or an object's properties to individual variables. While we have always been able to break complex objects and arrays down into simpler types, TypeScript provides a clean and elegant way to break these types down using REST parameters, which can deconstruct both objects and arrays.

In order to understand what REST properties are, we first need to understand how to deconstruct an object or an array. We are going to start off by deconstructing the following object literal, as follows:

let guitar = { manufacturer: 'Ibanez', type : 'Jem 777', strings : 6 };

One way that we could deconstruct this is by using the following:

const manufacturer = guitar.manufacturer;
const type = guitar.type;
const strings = guitar.strings;

While this works, it's not very elegant and there's a lot of repetition. Fortunately, TypeScript adopts the JavaScript syntax for a simple deconstruction like this, which provides a much neater syntax:

let {manufacturer, type, strings} = guitar;

Functionally, this results in the same individual items as the original implementation. The name of the individual properties must match the names of the properties in the object we are deconstructing—that's how the language knows which variable matches with which property on the object. If we need to change the name of the property for some reason, we use the following syntax:

let {manufacturer : maker, type, strings} = guitar;

The idea behind a REST operator on an object is that it applies when you take a variable number of items, so we are going to deconstruct this object into the manufacturer and the other fields are going to be bundled into a REST variable, as follows:

let { manufacturer, ...details } = guitar;
The REST operator must appear at the end of the assignment list; the TypeScript compiler complains if we add any properties after it.

After this statement, details now contains the type and strings values. Where things get interesting is when we look at the JavaScript that has been produced. The form of destructuring in the previous example is the same in JavaScript. There is no equivalent to the REST property in JavaScript (certainly in versions up to ES2018), so TypeScript produces code for us that gives us a consistent way to deconstruct more complex types:

// Compiled as ES5
var manufacturer = guitar.manufacturer, details = __rest(guitar, ["manufacturer"]);
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) &&
e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length;
i++) if (e.indexOf(p[i]) < 0)
t[p[i]] = s[p[i]];
return t;
};

Array destructuring works in a similar fashion to object destructuring. The syntax is virtually identical to the object version; the differences being that it uses [ ] to destructure in place of { }, which the object version uses, and that the order of the variables is based on the position of the item in the array.

The original method of destructuring an array relied on the variable being associated with an item at a certain index in the array:

const instruments = [ 'Guitar', 'Violin', 'Oboe', 'Drums' ];
const gtr = instruments[0];
const violin = instruments[1];
const oboe = instruments[2];
const drums = instruments[3];

Using array destructuring, we can change this syntax to be much more concise, as follows:

let [ gtr, violin, oboe, drums ] = instruments;

Knowing that the TypeScript team are good at providing us with a consistent and logical experience, it should come as no surprise that we can also apply REST properties to arrays, using similar syntax:

let [gtr, ...instrumentslice] = instruments;

Yet again, there is no direct JavaScript equivalent, but the compiled TypeScript shows that JavaScript does provide the underlying fundamentals and the TypeScript designers have been able to elegantly roll this in using array.slice:

// Compiled as ES5
var gtr = instruments[0], instrumentslice = instruments.slice(1);