TypeScript の strict モードを本番コードに有効化してみた話
tsconfig.json に strict: true を追加したら大量のエラーが出ました。何が起きたのか、どう対処したかをまとめます。
🙌 結論から
TypeScript の strict: true は、怖がって後回しにするより、早めに有効化したほうがコードの品質がかなり変わるので導入するなら最初がいいですね。
実際に仕事で使っているプロジェクトに有効にしてみたところ、100件近いエラーが出ました。
最初は「こんなに・・・?」と少し引きましたが、一個ずつ追っていくと 本当に潜在的なバグになっていたものが複数あった ので、結果的に早めに対処できてよかったです^^
型エラーを一つずつ直していく作業は手間ですが、後で本番障害として発覚するよりは相当楽 です。
💡 strict オプションで有効になる主なチェック
tsconfig.json に "strict": true を追加すると、複数の厳格なチェックがまとめて有効になります。
実際に仕事で引っかかったのは以下の2つが特に多かったです。
strictNullChecks:nullやundefinedを型として明示的に扱う必要があるnoImplicitAny: 型が推論できない変数に暗黙のanyを許可しない
これ以外にも strictFunctionTypes、strictBindCallApply などが有効になりますが、こちらで引っかかるケースは比較的少なかったです。
strictNullChecks と noImplicitAny の2つで、出てくるエラーのほとんどは説明できました。
👀 実際に有効にしたら出てきたエラーたち
一番多かったのは strictNullChecks 絡みです。
たとえば、APIのレスポンスを受け取って処理する関数で、⇩のようなコードが散在していました。
function getUserName(user: User | null): string {
return user.name; // Object is possibly 'null'.
}
user が null になりうるのに、そのまま .name にアクセスしているパターンです。
仕事の現場で実際に動いているコードだったので、「これ、null が来たとき落ちるのでは・・・?」と調べたら、案の定そのルートは未テストでした。
次に多かったのが noImplicitAny です。
function parseConfig(data) { // Parameter 'data' implicitly has an 'any' type.
return data.setting;
}
引数に型をつけていない関数が、レガシーコードの中にかなりありました。
こういった箇所は、型をつけることで 「この引数は本当に何が来るのか」を改めて考える 機会にもなります。
✨ 対処してわかったこと
エラーを一個ずつ直していくと、意外と面白いことに気づきます。
型エラーが出た箇所は、だいたい以下のどれかでした。
nullチェックが抜けている(潜在的なバグ候補)- 引数の型が曖昧なまま使われている(意図が読めない関数)
anyでごまかされていた(型安全の穴)
どれも「動いているからOK」ではなく、コードの意図が不明確になっている箇所 でした。
特に null チェック漏れは、本番で Cannot read properties of null として出てくるタイプのバグです。
ここで先に潰せたのは、かなりありがたいです。
対処の基本は3パターンで、可能なら3番目が一番きれいです。
if (value !== null)でガードを入れるvalue!の非nullアサーション(本当に来ないと確信できる場合のみ)- 型定義を見直して、そもそも
nullを許容しない設計に直す
👍 まとめ
strict: true の有効化は、最初にエラーが大量に出て気が重くなりますが、潜在的なバグを先に発見できる という点ではかなり価値があります。
新規プロジェクトなら最初から有効にするのが理想です。
既存プロジェクトに後から入れる場合は、// @ts-nocheck でファイル単位でいったんスキップしながら、少しずつ直していく方法が現実的でした。
私も最初は「後回しにしてもいいかな・・・」と思っていましたが、実際にやってみると発見が多く、コードへの理解も深まりました。
TypeScript を使っているプロジェクトでまだ有効にしていないなら、ぜひ一度試してみてほしいです🙏