io-ts を使った実行時型チェック(TypeScript)

こんにちは、ウィルゲート開発室の岡田(@okashoi)です。

今回は、社内 LT 会で話した io-ts の紹介を記事にしました。

型を明示するモチベーション

TypeScript は漸進的型付けができる言語です。

型を明示するモチベーションは多岐に渡りますが、多くの人に効果を実感してもらいやすいのが、エディタや IDE において補完が効くことでしょう。

補完が効いている様子

さて、ここで JSON を返す Web API からデータを取得する例を考えます。

const response = await (await fetch(url)).json();

この定数 response の中身は実行してみるまでわかりません。

当然、エディタや IDE によってプロパティ等が補完されることもありません。

定数 response は any とみなされる

io-ts を使った実行時型チェック

上記の例ように「実行されるまで変数や定数にどんなデータが入っているのかわからない」状況に対しては、「実行時に型のチェックを行いチェックを通っていればその型であるとみなす」というアプローチを取れます。

そのような手段や、機能を提供するライブラリには様々なものが存在していますが、その中から今回は io-ts を紹介します。

github.com

導入

io-ts は npm でインストールできます。 同時に fp-ts もインストールしておきます。

npm i fp-ts io-ts

使い方

はじめに io-ts 所定の方法で型を定義します。

import { Right } from 'fp-ts/lib/Either';
import * as t from 'io-ts';

// io-ts 所定の方法で型を定義
const User = t.type({
  id: t.string,
  name: t.string,
});

その後、型がわからない値を decode() メソッドに渡して実行することで、その値が定義された型の値として正しいかを判定してくれます。

import { Right } from 'fp-ts/lib/Either';
import * as t from 'io-ts';

// 略

const responseRaw = await (await fetch(url)).json();

// 型がわからない値に対して decode
const response = User.decode(responseRaw);

if (isRight(response)) { // その型の値として正しいときに true
  // ...
}

isRight()true となった場合、それ以降その型の値として扱われます。

isRight()true となった場合、その値の right プロパティをその型の値として扱えます(実際には right プロパティに直接アクセスせず、主に fp-ts/Either/fold あたりを経由して使うことになると思います)。

io-ts による実行時型チェックのおかげで補完が効くようになった

所感など

このように io-ts を使うことで、Web API レスポンスなど事前に型を付けられない値を型安全に扱えるようになります。 型の定義についても、io-ts 所定の方法を用いて柔軟な定義可能です。

一方で、その独自の型定義の記法を覚えないといけない点はデメリットでもあります。

また、(fp-ts をインストールしていることからも読み取れるように)関数型プログラミング的なアプローチを取っており、ドキュメント等を理解するためにそのあたりの前提知識が必要になる点にも留意が必要でしょう。

実現したいことに対して、上記のデメリットを許容できるかが使い所を判断するポイントになりそうです。