TL;DR
- TypeScript を最大限に活用するための 83 項目のアドバイスを、実践的なコードとともにまとめた実用書である。
- TypeScript の基本を身につけた初級者が、中級者、そしてエキスパートへ進むための本である。
対象読者
入門書ではない。TypeScript の基本を一通り学んだ人が、真に「effective な」TypeScript のコードを書けるようになるための本である。TypeScript は柔軟で表現力の高い型システムを持ち、JavaScript のコミュニティに広く浸透している。一方で高度な機能が多く、それらを使いこなせる開発者は多くない。本書は、適切なコードの書き方を根拠とともに示している。
目次
TypeScriptとは何か
- TypeScriptとJavaScriptの関係を理解する
- どのTypeScriptオプションが使われているか把握する
- コード生成は型に依存しないことを理解する
- 構造的型付けに慣れる
- any型の使用を制限する
TypeScriptの型システム
- エディターを使って型システムを調査、探求する
- 型を値の集合として考える
- 型空間のシンボルと値空間のシンボルの見分け方を知る
- 型アノテーションを型アサーションより優先的に使用する
- ラッパーオブジェクト型(String、Number、Boolean、Symbol、BigInt)を使用しない
- 余剰プロパティチェックと型チェックを区別する
- 可能なら関数式全体に型を適用する
- type(型エイリアス)とinterfaceの違いを知る
- readonlyを使用して変更にまつわるエラーを避ける
- 型演算とジェネリック型を使って重複を避ける
- インデックスシグネチャよりも適切な代替手段を使う
- 数値型のインデックスシグネチャを避ける
型推論と制御フロー解析
- 推論可能な型でコードを乱雑にしない
- 異なる型には異なる変数を使う
- 変数の型がどのように決まるか理解する
- オブジェクトを一度に構築する
- 型の絞り込みを理解する
- エイリアスを作成したら一貫してそれを使う
- 型推論に文脈がどう使われるか理解する
- 進化する型を理解する
- 関数型の標準APIやライブラリを使って型の流れを促進する
- コールバックの代わりにasync関数を使用して型の流れを改善する
- クラスやカリー化を使って型パラメーターを段階的に割り当てる
型設計
- 有効な状態のみ表現する型を作る
- 入力には寛容に、出力には厳格に
- 型情報をドキュメントで繰り返さない
- nullやundefinedを型エイリアスに含めない
- null値を型の外側に押しやる
- ユニオンを含むインターフェイスよりも、インターフェイスのユニオンを選択する
- stringよりもそれに代わる、より精度の高い型を選択する
- 特別な値には専用の型を使用する
- オプションプロパティは限定的に使用する
- 同じ型のパラメーターの繰り返しを避ける
- 差異のモデリングより型の統一を優先する
- 正確でない型より精度の低い型を選択する
- ドメインの言語を使って型を命名する
- たまたま目にしたデータに基づく型を避ける
不健全性とany型
- 可能なかぎり狭いスコープでany型を使う
- anyをそのまま使うのではなく、より具体的な形式で使う
- 安全でない型アサーションを、適切に型付けされた関数の内部に隠す
- 型が不明な値には、anyではなくunknownを使う
- モンキーパッチではなく、より型安全なアプローチを採用する
- 健全性の罠を回避する
- 型カバレッジを監視し、型安全性のリグレッションを防ぐ
ジェネリックと型レベルプログラミング
- ジェネリックを型に対する関数と考える
- 不必要な型パラメーターを避ける
- オーバーロードシグネチャより条件型を優先的に使用する
- 条件型のユニオンでの分配を制御する
- テンプレートリテラル型を使ってDSLや文字列間の関係をモデリングする
- 型のテストを書く
- 型の表示に配慮する
- 再帰的なジェネリック型は末尾再帰にする
- コード生成を複雑な型の代替手段として検討する
TypeScriptレシピ集
- never型を使って網羅性チェックを行う
- オブジェクトに対して反復処理する方法を知る
- Record型を使って値の同期を保つ
- レストパラメーターとタプル型を使って、可変長引数の関数をモデリングする
- never型のオプションプロパティを使って、排他的論理和をモデリングする
- 名前的型付けのためにブランドを使うことを検討する
型宣言と@types
- TypeScriptと@typesはdevDependenciesに追加する
- 型宣言の依存関係に関わる3つのバージョンを理解する
- パブリックなAPIで使われるすべての型をエクスポートする
- APIのコメントにTSDocを使う
- コールバックのthisがAPIの一部なら、それに型を与える
- 型を部分的にコピーして依存を断ち切る
- モジュールオーグメンテーションを使って型を改善する
コードを書いて実行する
- TypeScriptの独自機能の使用を避け、ECMAScriptの機能を使う
- ソースマップを使ってTypeScriptをデバッグする
- 実行時に型を再構築する方法を知る
- DOMの型階層を理解する
- ターゲットとする環境の正確なモデルを作る
- 型チェックとユニットテストの関係を理解する
- コンパイラーのパフォーマンスに注意を払う
コードのモダン化とTypeScriptへの移行
- モダンなJavaScriptを書く
- @ts-checkとJSDocを使ってTypeScriptを試す
- allowJsを使ってTypeScriptとJavaScriptを共存させる
- 依存関係グラフの下から上へモジュールごとに移行する
- noImplicitAnyを有効にするまで、移行が完了したと考えない
付録B 推奨事項の実践法
感想
コードを動かしながら読むために、最初は Deno を使うつもりだった。しかし、コンパイラオプションも設定できる TS Playground のほうが楽だった。なお、Node.js も v23.6.0 から、追加の設定なしで TypeScript を直接実行できるようになったらしい。
1 章ずつおすすめの項目を選んで、社内で共有したい。訳者の方の講演では、各章から「推し」(共感したもの、面白かったもの、勉強になったもの)を選んで紹介していた。それに倣って、自分の推しを章ごとに挙げておく。
- 1 章: 項目3 コード生成は型に依存しないことを理解する
- 2 章: 項目7 型を値の集合として考える
- 3 章: 項目22 型の絞り込みを理解する
- 4 章: 項目33 null値を型の外側に押しやる
- 5 章: 項目48 健全性の罠を回避する
- 6 章: 項目53 条件型のユニオンでの分配を制御する
- 7 章: 項目63 never型のオプションプロパティを使って、排他的論理和をモデリングする
- 8 章: 項目70 型を部分的にコピーして依存を断ち切る
- 9 章: 項目72 TypeScriptの独自機能の使用を避け、ECMAScriptの機能を使う
- 10 章: 項目82 依存関係グラフの下から上へモジュールごとに移行する
講演の内容とは関係ないが、スライド上で型にカーソルを合わせると詳細が表示されるのに驚いた。Slidev を使うと、このように型を表示できるらしい。