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 で変更が出ないことを確かめる。
キーワード
- コード生成
- チューリング完全
- タグ付きテンプレート
- 型宣言ファイル
- CI
- Git フック
- Rust
- TypeScript