TL;DR

  • 型で何でも解決するのが最適とは限らない。型が複雑になりそうなら、コード生成でコードと型を作ることを検討する。
  • 生成したコードが古くならないよう、CI などで定期的に生成して差分がないかを確かめる。

内容

型で解決するのが最適とは限らない

TypeScript の型システムはチューリング完全なので、理論上はどんな計算もできる。しかし、いつも型で解決するのが最適とは限らない。SQL クエリのパーサがその例である。

型が複雑になりそうなときは、コードと型を生成すること(codegen)を検討するとよい。コード生成には次の利点がある。

  • 生成ツールは TypeScript に限らず、好きな言語で書ける。Rust のように型がより厳密な言語で実装してもよい
  • 型の表示をコントロールできる。たとえば snake_case の型名が気に入らなければ、sed などのテキスト処理ツールで加工できる
  • コンパイラや言語サービスの負荷が小さい

例: PgTyped

PgTyped は、TypeScript のコードの中にタグ付きテンプレートで書いた SQL クエリを実際のデータベースと照合し、入出力の型を含む型宣言ファイルを生成する。型宣言ファイルは次のコマンドで生成する。

npx pgtyped -c pgtyped.config.json

生成したコードを同期させる

生成したコードが元と同期していることを保証するため、生成は定期的に実行する必要がある(Effective Rust 項目32 CIシステムを設定しよう)。たとえば CI 上や、Git フックの pre-push でコードを生成し、git diff で変更が出ないことを確かめる。

キーワード