TypeScript の Template Literal Types でAPI のイベント名を型安全にした話
WebSocket のイベント名や API パスを string 型で渡していたコードに Template Literal Types を導入したところ、補完が効くようになりタイポによるバグがかなり減りました。
🙌 結論から
TypeScript の Template Literal Types を使うと、string 型として素通しにしていた文字列を、特定のパターンに絞った型として扱えるようになります!
WebSocket のイベント名や API のエンドポイントパスをまるごと string で渡していたコードに導入したところ、補完が効くようになり、タイポが原因のバグがかなり減りました(^o^)/
使い方はそれほど難しくないのに、知っている人と知らない人で型の表現力がだいぶ変わります。
💡 Template Literal Types とは
TypeScript 4.1 から使えるようになった機能で、テンプレートリテラルの構文を型の世界に持ち込んだものです。
たとえば、こんなふうに書けます。
type EventName = `on${Capitalize<string>}`;
// "onClick" | "onChange" | "onFocus" など "on〇〇" の形を表す型
これを使うと "onClick" は OK、"click" は NG という制約を型で表現できます!
より実用的な例だと、ユニオン型との組み合わせがよく使われます。
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
type Endpoint = `/api/${string}`;
type ApiConfig = {
method: HttpMethod;
url: Endpoint;
};
こうすると url に "https://example.com" を渡した瞬間に型エラーになり、うっかり外部 URL を渡すミスを防げます。
👀 実際に使った例
私が最初に導入したのは、WebSocket のイベント名の管理でした。
以前は socket.on('user:join', handler) のようにイベント名を直接文字列で書いていて、'user:jion' というタイポが発生しても実行時までわかりませんでした(´・ω・`)
そこで以下のように型を定義しました。
type Namespace = 'user' | 'room' | 'message';
type EventVerb = 'join' | 'leave' | 'send' | 'receive';
type SocketEvent = `${Namespace}:${EventVerb}`;
// 有効: "user:join", "room:leave", "message:send" ...
// 無効: "user:jion" → コンパイルエラーになる!
これだけで SocketEvent 型には Namespace × EventVerb の組み合わせしか入れられなくなります。
エディタの補完もきちんと機能して、タイポの心配がなくなったのがかなりありがたかったです!
🤔 ハマりポイント
組み合わせ数が爆発的に増える点だけ注意が必要です(・_・;)
type A = 'a1' | 'a2' | 'a3';
type B = 'b1' | 'b2' | 'b3';
type C = 'c1' | 'c2' | 'c3';
type Combined = `${A}-${B}-${C}`; // 3×3×3 = 27通り
ユニオン型の組み合わせが増えると TypeScript の型チェックが重くなることがあります。
10〜20 パターン程度であれば問題ないケースがほとんどです。
ドメインが広い場合は string を使いつつコメントでパターンを示す、というバランスが現実的かもしれません。
もう一点、Capitalize<T> などのユーティリティ型を活用すると定義が簡潔になりますが、IDE の型ヒントが少し読みづらくなることがあります。
実際に使いながらトレードオフを確認していくのがいいと思います!
パパ系Webエンジニア〜愛用ガジェット一覧 🛍️
この記事を書いている作業環境のガジェットを楽天ROOMにまとめています ✨ 在宅エンジニアのデスク作りの参考にどうぞ 🙌
🙌 まとめ
- Template Literal Types は TypeScript 4.1 以降で使える
- ユニオン型と組み合わせると、文字列の「パターン」を型で制約できる
- イベント名・API エンドポイント・CSS クラス名など、規則性のある文字列に相性がいい
- 組み合わせ数が多くなりすぎると型チェックが重くなる点に注意
string で素通しにしている箇所が多いと感じているなら、まず 1〜2 箇所だけ試してみるのがおすすめです(^^)
比較的小さい変更なのに、補完とエラーチェックの恩恵がすぐに感じられますよ!