Contents
なぜ今「TypeScriptのstrict」を段階的にONにすべきか(Next.js視点)
TypeScriptのstrict(厳格モード)は、バグになりやすい「曖昧な書き方」をコンパイル時に検知してくれる設定です。ところが、既存のプロジェクト(特に長く運用しているNext.jsのWebサイトや社内ポータル)にいきなりstrictをONにすると、数百〜数千のエラーが一気に出て、現場が止まります。結果として「TypeScriptは面倒」「開発が遅い」という印象が残り、改善が頓挫しがちです。
一方で、strictを導入しないまま放置すると、リファクタリング時に不具合が混ざりやすくなり、確認工数や障害対応コストが増えます。情シスや管理側の立場だと、「ベンダーに任せているが品質が見えない」「改修のたびに見積が膨らむ」「担当者が替わると引き継ぎが難しい」といった課題に直結します。
Next.jsでは、ページやAPIルート、Server Components/Client Components、環境変数、fetch、フォーム入力、CMSデータなど、型が曖昧になりやすい境界が多いのが特徴です。strictはここを強化し、仕様変更に強いコードに寄せるのに有効です。
本記事では、専門知識がない方でも意思決定できるように、strictを「一気にON」ではなく段階的に厳しくする実務手順を、Next.jsのよくある落とし穴(環境変数、APIレスポンス、フォーム、外部CMS)と合わせて説明します。目標は「開発を止めずに品質を上げる」ことです。
3分でできる! 開発費用のカンタン概算見積もりはこちら
strictを「全部ON」にしないための設計:最小リスクで始める方針
TypeScriptのstrictは、実際には複数のチェック項目(例:nullの扱い、暗黙anyの禁止、関数引数の厳格さなど)の集合体です。つまりstrict=trueは“全部入り”で、既存のNext.jsプロジェクトだと影響が大きくなります。安全に進めるコツは、次の2つの考え方です。
- チェック項目を小分けにして、順番にONにする(段階導入)
- 影響範囲を限定して、重要な部分から固める(境界からの型付け)
特に「境界」とは、アプリの外からデータが入ってくるところです。Next.jsで言えば、環境変数、APIの入力/出力、CMS、DB、フォーム入力、Cookie/headersなどです。ここが曖昧だと、内部のコードに“型が怪しい値”が流れ込み、どこで壊れたか追いづらくなります。逆に、境界で型を確定できれば、内部のコードは自然と安全になります。
意思決定としては、まず「strictを目標にする」ことだけ決め、初回はstrictをOFFのまま、個別項目だけ少しずつONにするのが現実的です。経営・情シス観点では、次のようなKPI(完了の定義)にすると進捗が見えます。
- CI(自動テスト/ビルド)でTypeScriptチェックが必ず走る
- 新規追加ファイルは原則strict相当で書く(既存は例外)
- 月次で「型エラー件数」「any使用数」「ts-ignore使用数」を減らす
これにより「次の改修から地雷が減る」状態を作れます。いきなり完璧を目指さず、改善が継続する仕組みを先に整えるのがポイントです。
準備:Next.jsプロジェクトで型チェックを“運用”に組み込む
段階導入でも、土台がないとすぐに崩れます。まずは「型チェックを必ず実行する」ことを仕組みにします。Next.jsはビルド時に型チェックが走ることが多いですが、環境や設定で抜ける場合があります。運用上の安心のため、明示的にコマンド化するのが有効です。
推奨する最低限の準備は次のとおりです。
- package.jsonに型チェック用のスクリプトを用意(例:
tsc --noEmit) - CI(GitHub Actions等)でPRごとに型チェックを実行
- ESLintと組み合わせて、危険な書き方(any、未使用変数等)も抑制
例:
{
"scripts": {
"typecheck": "tsc --noEmit",
"lint": "next lint",
"build": "next build"
}
}
また、Next.js特有の注意点として、App Router(app/)を使っている場合、Server/Clientの境界で型の扱いがぶれやすいです。たとえば、Server Componentで取得したデータをClient Componentに渡すとき、JSONシリアライズできない値(DateやMapなど)が混ざると問題になります。strict導入前でも、「渡すデータはプレーンなオブジェクトに整形する」というルールを決めておくと、型付けが進みやすくなります。
さらに、情シス・管理側として重要なのは「例外を作りすぎない」ことです。ts-ignore(型エラーの黙殺)を許すと、一時的には進みますが、後で負債になります。どうしても必要な場合は、期限と理由をコメントに残す、またはチケット化して回収可能にしておくと、運用品質が上がります。
3分でできる! 開発費用のカンタン概算見積もりはこちら
段階的にstrictへ近づけるtsconfig手順(おすすめの順番)
ここからが本題です。strictを安全にONにするには、tsconfig.jsonでチェック項目を段階的に増やします。プロジェクトの規模にもよりますが、基本は「エラーが爆発しにくいものから」入れます。以下は現場で進めやすい順番の一例です。
最初にON:noImplicitAny(暗黙anyの禁止)
「型が書かれていないからany扱いになる」状態は、バグの温床です。noImplicitAnyをONにすると、型が不明な場所が可視化されます。既存コードに影響は出ますが、対応方法は比較的単純で、型注釈を足す・関数引数に型を付ける・型推論できる形に直す、といった作業になります。“どこが曖昧か”を洗い出すフェーズとして効果的です。
次にON:strictNullChecks(null/undefinedの扱いを厳密化)
業務システムの障害原因として多いのが、「想定していない空値」です。フォーム未入力、APIが一時的に欠損、CMSの項目が未設定などで、undefinedが混ざります。strictNullChecksをONにすると、これがコンパイル時に見える化されます。
対応の基本は、「空のときにどうするか」を仕様として決めることです。例:未入力ならエラー表示、未設定なら“未登録”と表示、など。技術だけでなく業務側の判断も必要になるため、ここは早めに合意を取るとスムーズです。
次にON:noUncheckedIndexedAccess(配列/辞書アクセスの安全性)
配列のarr[0]やオブジェクトのobj[key]は、存在しない可能性があります。これを厳密にすると、境界データ(API/CMS)の取り扱いが堅くなります。Next.jsでは、searchParamsや動的ルートのパラメータなどで「キーが存在しない」ケースがあるため、実務で役立ちます。
最後にまとめて:strict=true(残りの項目も含めて)
上記がある程度片付くと、strict=trueに近づけます。ただし、strictFunctionTypes等の影響で大きく崩れる場合があります。おすすめは、strict=trueにする前に、既存の個別フラグがすでにONになっている状態を作ることです。そうすると、strict=trueにした際の差分が小さくなります。
導入例(段階導入のイメージ):
{
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "ES2020"],
"jsx": "preserve",
"moduleResolution": "Bundler",
"noEmit": true,
"strict": false,
"noImplicitAny": true,
"strictNullChecks": false,
"noUncheckedIndexedAccess": false
}
}
一定期間運用してエラーが落ち着いたら、strictNullChecks、noUncheckedIndexedAccessを順にON。最後にstrict=trueへ、という流れです。重要なのは、“ONにしたら戻さない”運用ルールにすることです。戻すと、改善が積み上がりません。
Next.jsで特に効果が出る「境界の型付け」:環境変数・API・フォーム
strictを進めるとき、最短で品質が上がるのは「境界」です。Next.jsで効果が出やすい3点を、非エンジニアの方にも判断できるように説明します。
環境変数(NEXT_PUBLICやサーバー側)の型安全
環境変数は文字列で渡ってくるため、数値や真偽値として扱うときに事故が起きます。また、設定漏れは本番障害に直結します。対策として、アプリ起動時に「必要な環境変数が揃っているか」をチェックし、足りなければ明確に落とすのが安全です。“起動時に失敗させる”のは悪ではなく、障害を早期発見する設計です。
例(概念):
const env = {
API_BASE_URL: process.env.API_BASE_URL,
};
if (!env.API_BASE_URL) {
throw new Error("API_BASE_URL is required");
}
API(Route Handler)入力/出力の固定
Next.jsのRoute Handler(例:app/api/…)は、外部からリクエストを受けるため、最も壊れやすい境界です。ここで「想定外の入力」を弾く、レスポンス形式を固定する、という2点が重要です。strictを入れると、曖昧なデータ構造をそのまま返している箇所が露呈します。
実務的には、APIの入出力に「型(TypeScriptの型)」を用意し、handlerの中で型に合わせて整形します。さらに一歩進めるなら、zod等でランタイム検証(実データ検証)を入れると、型と実データのズレを防げます。情シス・管理側の観点では、“API仕様書がなくても壊れにくい”状態を作れるのがメリットです。
フォーム(入力値は必ず文字列から始まる)
Next.jsのフロント側では、フォーム入力はまず文字列として入ってきます。数値項目、日付、チェックボックスなどをそのまま扱うと、null/undefinedや型変換ミスが起きがちです。strictNullChecksをONにすると、未入力時の扱いが強制的に設計されます。
対策は「画面での入力値 → 送信データ(DTO) → サーバーでの検証」という流れを作ることです。フォームの段階で変換・検証し、サーバーでも再検証する(フロントだけに依存しない)のが堅いです。“二重チェック”はコストではなく保険で、特に社内向け業務システムでは効きます。
3分でできる! 開発費用のカンタン概算見積もりはこちら
エラーが大量に出たときの現実的な潰し方(開発を止めない)
段階導入でも、strict系の設定を上げるとエラーが増える瞬間があります。ここで重要なのは「全件を一気に直す」ではなく、作業を分割してプロジェクトを止めないことです。現場でよく効く進め方をまとめます。
- 新規・変更ファイルから先に厳密化(触った場所は必ず改善する)
- 境界(API/環境変数/CMS)から直す(波及効果が大きい)
- 共通型(types/)を整備して重複を減らす
- 暫定対応は“安全側”に倒す(unknown→検証→型確定)
特に「anyをunknownに置き換える」は、strict導入でよく使う手です。anyは何でも通してしまうのに対し、unknownは使う前に確認(型の絞り込み)が必要になります。つまり、unknownにするだけで、危険な箇所がコード上で目立つようになります。
また、型エラーを黙らせるためにas anyを多用すると、strict導入の意味が薄れます。どうしても変換が必要なら、変換する場所を境界に寄せ、アプリ内部では型が保証された値だけを扱うのが理想です。“アプリ内部にanyを持ち込まない”だけでも事故が減ります。
管理側の運用としては、改善タスクを「機能改修のついで」に混ぜるのがおすすめです。たとえば、次の改修で触る画面の周辺だけstrictNullChecks対応を進める、といった形です。専用期間を確保できるなら理想ですが、現実には難しいことも多いため、改善を日常業務に溶け込ませる設計が成功率を上げます。
よくある失敗と回避策:コスト増を防ぎ、品質を上げる
strict導入は「やり方」を間違えると、コストだけ増えて効果が出ません。非エンジニアの方がプロジェクトを見ていて気づきやすい、よくある失敗と回避策を整理します。
- 失敗:いきなりstrict=trueにして炎上
回避:個別フラグで段階導入し、境界から直す - 失敗:ts-ignoreやas anyで“通すだけ”が増える
回避:例外はチケット化、期限を置く。unknown→検証の流れを採用 - 失敗:型だけ増えて実データが保証されない(API/CMSの中身が違う)
回避:zod等でランタイム検証、もしくはサーバー側で整形してから返す - 失敗:型が各所に散らばり、修正のたびに破綻する
回避:共通の型定義(DTO)を用意し、変更点を1か所に集約
特に経営・情シスの立場で押さえたいのは、「strict導入=開発者のこだわり」ではなく、運用コスト(障害対応、調査、引き継ぎ)を下げる投資だという点です。担当者が変わっても読みやすく、改修時に想定外が起きにくい状態を作れます。
また、Next.jsはアップデートが速く、周辺ライブラリも頻繁に変わります。strictで型を固めておくと、アップデート時の影響範囲が見えやすくなり、移行コストを下げられます。これは中長期で大きな差になります。
株式会社ソフィエイトのサービス内容
- システム開発(System Development):スマートフォンアプリ・Webシステム・AIソリューションの受託開発と運用対応
- コンサルティング(Consulting):業務・ITコンサルからプロンプト設計、導入フロー構築を伴走支援
- UI/UX・デザイン:アプリ・Webのユーザー体験設計、UI改善により操作性・業務効率を向上
- 大学発ベンチャーの強み:筑波大学との共同研究実績やAI活用による業務改善プロジェクトに強い
3分でできる! 開発費用のカンタン概算見積もりはこちら
まとめ
TypeScriptのstrictは、Next.jsの運用で起きがちな「データの欠損」「想定外の入力」「仕様変更による事故」を減らす有効な手段です。ただし、既存プロジェクトでいきなりstrict=trueにするとエラーが爆発し、開発が止まるリスクがあります。そこで、チェック項目を小分けにして段階的にONにし、環境変数・API・フォームなどの「境界」から型を固めるのが安全です。
進め方の要点は、型チェックをCIに組み込み、新規・変更箇所から改善し、例外(ts-ignoreやas any)を管理して負債化させないことです。strict導入は短期的には作業が増える場面もありますが、中長期では障害対応や引き継ぎコストを下げ、改修の見積もりを安定させます。Next.jsを安心して育てていくために、止めない形でstrictへ近づけていきましょう。
コメント