Typescript & Immutable.jsで快適データ構造操作

今回は、業務で使っているTypescriptと、javascriptのデータ構造ライブラリであるImmutable.jsの合わせ技についてご紹介したいと思います。

Typescriptとは

MicroSoft社が開発を始め、今やGithubOSSとして開発が続けられているAltJS(JSにコンパイルできる言語)の一つです。

TypeScript - JavaScript that scales.

この言語の一番の特徴といえば、静的な型付けによるコンパイル時型チェックです。Typescriptにはnumber,string,booleanなどのプリミティブ型を始め、Java等で馴染みのあるInterfaceや、Classも存在します。また、ジェネリクスによる型のパラメータ化もできます。

もちろん、コンパイル後にはこれらの情報はほぼ落ちてしまうのですが、型チェックの恩恵が受けられるので、主にプログラミングの際の補完がかなり優秀です。今回はこの補完という要素についてfocusしてみたいと思います。

Immutable.jsとは

https://facebook.github.io/immutable-js/

こちらは、javascriptにおけるイミュータブルなデータ構造を提供してくれるライブラリです。プリミティブな実装にもあるArrayやMapの他にも、SetやListなんかもあります。 javascriptは組み込みのデータ構造操作メソッドがあまり充実しておらず、またimmutable/mutableの区別が曖昧なものが多いです。このライブラリは、その問題を解消し、元データに手を加えることなく様々な操作を可能とします。

Immutable.jsとjavascriptの相性

さて、このImmutable.jsですが、ドキュメントを見てみるとなにやらjavascriptらしくない(?)型要素が満載のドキュメントになっています。 C++Javaなどに慣れている人ならばピンと来るのですが、ここで使われているのはジェネリクスというものです。 たとえばMap<K, V>という型は、Key(連想配列の添字)がK型、値(連想配列の中身)がV型であるということを表しています。ここでKとVは型を表すパラメータとして使われています。 そんなもの動的型付けの前じゃ意味ないじゃないか!という意見はごもっともです。実際javascript上では、この型付けによる恩恵はほぼありません。 (とはいえ、リスト操作に関しては組み込みのものよりも多くのメソッドがあり、またImmutable性を保証してくれるので使うモチベーションは大いにあります。)

型付けによる恩恵

もちろんImmutable.jsの型定義ファイルは公開されており、Typescriptでこの型の恩恵を大いに受け取ることができます。コンパイル時チェックもさることながら、コーディング中の補完もかなり優秀です。

たとえば、Aくんが以下のようなプログラムを書いたとします。中身はとても適当なのですが、とりあえずリストに対して複雑な処理がしたいということだけ察してください。

// user.ts
interface User {
    id: number;
    name: string;
    friends: User[];
}

export default User;
// main.ts
import User from './user';
import * as Immutable from 'immutable';

let bob: User = {
    id: 1,
    name: "Bob",
    friends: []
};

let alice: User = {
    id: 2,
    name: "Alice",
    friends: [bob]
};

let john: User = {
    id: 3,
    name: "John",
    friends: [bob]
};

let eliza: User = {
    id: 4,
    name: "Eliza",
    friends: [alice]
};

let users: User[] = [bob, john, alice];

Immutable.Seq(users)
    .sortBy((user) => user.id)
    .map((user) => {
        user.friends.push(eliza);
        return user;
    })
    .filter((user) => user.name.length > 4)
    .reverse()
    .last();

上記main.tsにおける最後のメソッドチェーンの結果はUser型であることが期待されますが、書いた後のAくんにはほんとにUser型が返ってくるかどうかわかりません。型エラーがあれば最終的にコンパイル時にわかるのでよいのですが、書いたそばからコンパイルするのは面倒です。本当は書いてる最中にわかればいいのに…そんな時に補完機能とその型の表示機能が役に立ちます!(ここではVisualStudioCodeを使用しています)

f:id:kota-inamori:20170221185606g:plain

すぐさまUser型であることがわかりました!その他にも、補完するときにそのドキュメントも表示されていることがわかるとおもいます。もちろん型を明示するのはプログラマの責任ですが、コンパイル時だけでなくコーディング時にもその恩恵を受けることができます。

まとめ

今回はTypescriptとImmutable.jsの組み合わせについてご紹介しました。型付けによる補完機能の強化はTypescript自体の特徴の一つではありますが、データ構造の操作という中身がわかりづらい操作をする場合だと、その恩恵が顕著に得られることがわかります。