TypeScriptにはランタイム型チェック機能がありません。
次のようなコードも正常にコンパイルされエラーが発生することなく動作します。
const x: string = JSON.parse("1");
これはパフォーマンスなどとのトレードオフなので仕方ないのですが、部分的に動的な型チェックをしたいときもあります。
このような時の解決策としてio-ts
を紹介します。
JSON Schema
などは型とスキーマを2つ書く必要があり大変です。
また大変なだけでなく型とスキーマが異なるといったバグを型システムでチェックすることが出来ません。
コードジェネレーターを使うことで解決できますが、TypeScript上で完結しないのでめんどくさいです。
このような問題はio-ts
を使うことで解決します。
ただし再帰型については型推論の関係で型とスキーマを2回書く必要がありますが、型チェックでスキーマと型が違っていればコンパイルエラーが発生します。
import * as t from "io-ts";
const hoge = t.type({
tag: t.literal("Hoge"),
x: t.string,
y: t.union([t.number, t.null]),
});
type Hoge = t.TypeOf<typeof hoge>;
/*
type Hoge = {
tag: "Hoge",
x: string,
y: number | null,
};
*/
hoge.is(JSON.parse(str));
もっと詳しい使い方はio-ts
のREADMEを見ればすぐ分かるのでこっちを見て下さい。
https://github.com/gcanti/io-ts
※ここから先はライブラリを使う分にはあまり知らなくていい情報です。
TSはデコレーターという例外を除いて、型情報から値を生成することは出来ません。
しかし、typeof
を使うことで値から型を生成することは出来ます。
そこでスキーマ情報をなるべく具象型で(例えば単にSchemeのような型ではなくSchemeの構造を完全に持っている型)持つように型推論を制御して、typeof
で値から型を作ることでこのような事が可能になります。
ちなみにTS3.4でas const
が入ったので今までより具象型で持つのが楽になりました。
これはio-tsに限らずTSを使う時に知っておくと役に立つ考え方です。
ちなみに作者のgcanti氏はfp-ts
の作者でもあり、他にもTSの型システムを最大限活用したライブラリを多数公開しているので見てみると面白いかもしれません。