TL;DR

内容

移行の順序

JavaScript から TypeScript へ移行するときは、依存関係グラフの下から上に向かって進める。依存関係グラフは madge で可視化できる。生成したグラフをトポロジカルソートすれば、各モジュールをどの順序で移行すればよいかが分かる。

最初に移行するのは、サードパーティのパッケージである。型が同梱されていないパッケージは、@types パッケージを別途インストールする。このとき、パッケージと型のバージョンは必ず一致させる。

npm i --save-dev @types/lodash

外部 API を呼び出すコードも早めに移行する。仕様書や DB スキーマのような信頼できる情報源があれば、そこから型を生成したほうがよい(項目42)。

移行時の注意

移行するときは、リファクタリングよりも型の追加に集中する。直近の目標は TypeScript への移行であり、設計の改善ではない。リファクタリングにまで手を出すと、作業が遅くなり、コードレビューも難しくなり、バグを生むリスクも高まる。

JSDoc と @ts-check を使っていた場合、TypeScript では JSDoc の型が強制されなくなるので、TypeScript に移行すると型安全性を失うことがある。たとえば次の num は暗黙の any になる。

/**
 * @param {number} num
 */
function double(num) {
  return 2 * num
}

この場合、IDE のクイックフィックスを使うと、JSDoc の型から型アノテーションを追加できる。型を追加したら、JSDoc からは型を消す(項目31)。

よく出るエラーと解決策

宣言されていないクラスのメンバー

JavaScript のクラスはメンバーを宣言しなくてもよいが、TypeScript では宣言が必要である。クイックフィックスを使えば、使われ方に基づいてメンバーの宣言を追加してくれる。ただし、使われ方から型を推測できない場合は any になる。

型が変化する値

const state = {}
//    ^? const state: {}
state.name = "New York" // 型エラー: Property 'name' does not exist on type '{}'.
state.capital = "Albany" // 型エラー: Property 'capital' does not exist on type '{}'.

修正が小さく済むなら、オブジェクトを一度に構築する(項目21)。

const state = { name: "New York", capital: "Albany" }

そうでなければ、const state = {} as State のように型アサーションを使う。型アサーションは避けるのが最善である(項目9)。しかし、今はリファクタリングより移行を優先し、TODO コメントや Issue を残して後で直してもよい。

キーワード