Advanced Static Types in TypeScript

This course explores the capabilities of TypeScript’s type system and shows how to use advanced static types in practice.

Watch the Course

Lodash and ECMAScript 2015

Lodash and Underscore are two well-known and popular JavaScript libraries that offer a plethora of functions which the language itself doesn't provide. They have always been quite easy to use, but starting with ECMAScript 2015, writing calls to the provided library functions will feel even more seamless.

Besides big novelties like a native module system, ECMAScript 2015 introduces smaller language features as well. Pattern matching, array destructuring, arrow functions, and string interpolation are some examples that lead to shorter, more expressive, and more readable code. We're going to look at how to use these features in conjunction with Lodash (or Underscore, for that matter).

Pattern Matching & Collection Partitioning

Lodash defines the _.partition function which expects as its arguments a collection and a predicate. It partitions the collection into two subsets, one containg all the elements matching the predicate and one containing all others. In the end, each element of the collection is included in one (and only one) of the subsets, just like you'd expect from a mathematical set partitioning.

The two partitions are returned as the elements of a two-element array. You'll always find the set of matching elements at index 0 and the set of non-matching elements at index 1. With ECMAScript 5, the current JavaScript version, partitioning an input array and then accessing the partitioned sets could look as follows:

var numbers = [4, 8, 15, 16, 23, 42];
var isEven = function(n) {
    return n % 2 === 0;
};

var partitions = _.partition(numbers, isEven);
var evens = partitions[0];
var odds = partitions[1];

// evens: [4, 8, 16, 42]
// odds: [15, 23]

With ECMAScript 2015, we can do better and make use of pattern matching and destructuring assignment for arrays. We know what the only two elements of the returned array represent, so we can directly assign both sets to two local variables:

let numbers = [4, 8, 15, 16, 23, 42];
let isEven = function(n) {
    return n % 2 === 0;
};

let [evens, odds] = _.partition(numbers, isEven);

// evens: [4, 8, 16, 42]
// odds: [15, 23]

Using the above syntax, the returned array is immediately destructured. Its first element is assigned to the variable evens, its second one to odds. Clean and readable, isn't it?

The process of destructuring arrays is fail-soft: If the array on the righthand side had three or more elements (which it never does for _.partition), all elements except the first two wouldn't have been assigned to any named symbol. In cases where the list of local variables on the lefthand side is longer than the array on the righthand side, all superfluous local variables receive the value undefined.

Arrow Functions & Inline Functions

Another feature of ECMAScript 2015 that we're going to look at in this post is the arrow function syntax. If you've done any programming in C#, you'll be familiar with lambda expressions and their use in conjunction with LINQ queries.

Arrow functions let you define functions in a very concise way that doesn't require the function keyword. Instead, a double arrow (aka "fat arrow") separates the argument list from the function body. For instance, the above definition of the isEven function can be shortened to a single line using an arrow function:

let isEven = (n) => { return n % 2 === 0 };

Because the body of the function consists of a single expression that is returned, we can omit both the return keyword and the braces. Also, the parentheses around the argument list are optional if exactly one argument is declared. We can therefore shorten the function definition even more:

let isEven = n => n % 2 === 0;

The brevity of arrow functions is especially useful for defining short functions that are passed to higher-order functions (functions accepting functions as parameters). Usually, simple functions defined using the arrow syntax are short enough to be written inline:

let numbers = [4, 8, 15, 16, 23, 42];
let [evens, odds] = _.partition(numbers, n => n % 2 === 0);

// evens: [4, 8, 16, 42]
// odds: [15, 23]

Function Chains & String Interpolation

When you transform array data in various ways, you usually perform multiple operations in a row. With a little help of Lodash, those transformations can be composed into a function chain through which all values are piped.

Assume we have listed all members of the Fellowship of the Ring:

let fellowship = [
    { name: "Gandalf", race: "Maiar" },
    { name: "Frodo",   race: "Hobbits" },
    { name: "Sam",     race: "Hobbits" },
    { name: "Merry",   race: "Hobbits" },
    { name: "Pippin",  race: "Hobbits" },
    { name: "Aragorn", race: "Men" },
    { name: "Legolas", race: "Elves" },
    { name: "Gimli",   race: "Dwarves" },
    { name: "Boromir", race: "Men" }
];

To count the number of representatives of each race in the fellowship, we can pass the fellowship variable to the global Lodash function and chain together all functions:

let races = _(fellowship)
    .groupBy("race")
    .map((members, race) => `${race} (${members.length})`)
    .sort()
    .join(", ");

// races: "Dwarves (1), Elves (1), Hobbits (4), Maiar (1), Men (2)"

Here, we use an interpolated string to generate the output containing the name and member count for each race. We also make use of an arrow function to specify how to map each element of the array.

Note that it's required to start and end the function chain with calls to _.chain and _.value when you're using Underscore (see Underscore's documentation). Those two functions add and remove a wrapper that enables the Underscore chaining syntax. Lodash has implicit function chaining and thus doesn't require explicit calls to set up a function chain.

Lodash also enables us to call sort and join directly as part of the chaining syntax and maps both functions to their native implementations.

Summary

As you've seen, JavaScript code calling Lodash (or Underscore) functions can benefit a lot from new language features defined by ECMAScript 2015. Pattern matching, array decomposition, arrow functions, and string interpolation make it possible to write terse yet readable code. Of course, these language features only make up a fraction of what's coming with ECMAScript 2015. I highly encourage you to check out this 90 minute overview of ECMAScript 6 for more information.

Learn Node