$ |
TypeScript 5.xの型レベルプログラミング、使いこなせてる奴ほぼいない説
$ █
型レベルプログラミングとは何か
TypeScript 5.xで追加された型レベル機能、正直に言って使いこなせてる人ほぼいない。僕の周りでも「Template Literal Typesすげー」で止まってる人が大半だ。型レベルプログラミングとは、TypeScriptの型システムそのものをプログラミング言語として使うアプローチのこと。値の世界ではなく、型の世界でロジックを組む。
これができると何が嬉しいかというと、コンパイル時にバグを潰せる範囲が劇的に広がる。ランタイムエラーを型エラーに変換できるわけだ。
Conditional Typesの実践パターン
まず基本のConditional Types。これを再帰的に使うのが型レベルプログラミングの第一歩。
type DeepReadonly<T> = T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
// ネストしたオブジェクトも全部readonlyになる
type Config = DeepReadonly<{
db: { host: string; port: number };
cache: { ttl: number };
}>;
これだけで「うっかりconfigを書き換えちゃった」系のバグが完全に消える。5.xではこの再帰の深さ制限も緩和されて、実用レベルになった。
Template Literal Typesで文字列を型で縛る
APIのパスとか、特定のフォーマットの文字列を型で縛れるのがTemplate Literal Types。これがマジで強い。
type ApiPath = `/api/${string}`;
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type RouteKey = `${HttpMethod} ${ApiPath}`;
// これはOK
const route: RouteKey = 'GET /api/users';
// これは型エラー
const bad: RouteKey = 'PATCH /api/users'; // Error!
ルーティング定義を型安全にできるのはデカい。Express使ってる人、これだけでも導入する価値ある。
satisfies演算子との組み合わせが最強
TypeScript 5.xで地味に最強なのがsatisfies演算子。型推論を保ちつつ型チェックできる。
const config = {
api: { url: 'https://example.com', timeout: 3000 },
db: { host: 'localhost', port: 5432 }
} satisfies Record<string, { [key: string]: string | number }>;
// config.api.url は string型として推論される(Record値型ではない)
config.api.url.toUpperCase(); // OK!
asで型を付けると推論が死ぬ問題をsatisfiesが解決した。これを知らない人がまだ多すぎる。
まとめ — 型レベルプログラミングは武器になる
正直、型レベルプログラミングは学習コストが高い。でも一度身につけたら、コードの安全性が段違いに上がる。特にライブラリ作者やフレームワーク開発者には必須スキルだと思う。「anyで逃げる」時代はもう終わり。型と向き合え。












>_ コメント