TypeScript の strict モードを本番コードに有効化してみた話

tsconfig.json に strict: true を追加したら大量のエラーが出ました。何が起きたのか、どう対処したかをまとめます。

🙌 結論から

TypeScript の strict: true は、怖がって後回しにするより、早めに有効化したほうがコードの品質がかなり変わるので導入するなら最初がいいですね。

実際に仕事で使っているプロジェクトに有効にしてみたところ、100件近いエラーが出ました。

最初は「こんなに・・・?」と少し引きましたが、一個ずつ追っていくと 本当に潜在的なバグになっていたものが複数あった ので、結果的に早めに対処できてよかったです^^

型エラーを一つずつ直していく作業は手間ですが、後で本番障害として発覚するよりは相当楽 です。

💡 strict オプションで有効になる主なチェック

tsconfig.json"strict": true を追加すると、複数の厳格なチェックがまとめて有効になります。

実際に仕事で引っかかったのは以下の2つが特に多かったです。

  • strictNullChecks: nullundefined を型として明示的に扱う必要がある
  • noImplicitAny: 型が推論できない変数に暗黙の any を許可しない

これ以外にも strictFunctionTypesstrictBindCallApply などが有効になりますが、こちらで引っかかるケースは比較的少なかったです。

strictNullChecksnoImplicitAny の2つで、出てくるエラーのほとんどは説明できました。

👀 実際に有効にしたら出てきたエラーたち

一番多かったのは strictNullChecks 絡みです。

たとえば、APIのレスポンスを受け取って処理する関数で、⇩のようなコードが散在していました。

function getUserName(user: User | null): string {
  return user.name; // Object is possibly 'null'.
}

usernull になりうるのに、そのまま .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 を使っているプロジェクトでまだ有効にしていないなら、ぜひ一度試してみてほしいです🙏