システム開発
約19分
更新

なぜTypeScriptなのか?保守性の高いコードベースの維持

執筆・編集Malake株式会社
まず押さえたいこと

TypeScriptは、JavaScriptに型の記述と静的な型チェックを加える言語です。型情報から変更の不整合を確認しやすくしますが、型定義だけで実行時の入力や業務処理の正しさが保証されるわけではありません。

この記事の要点

TypeScriptは、引数・返り値・プロパティの不整合を開発時に確認しやすくし、変更の影響を見つける助けになります。ただし型は実行時の値を検査しないため、APIやフォームから届く値は実行時に検証してから使います。JavaScriptからの移行は一括で書き換えず、今の動作とテストを確かめたうえで、対象と厳格さを段階的に広げます。型チェック・入力検証・テスト・CIで何を確かめ、何が未確認かを記録し、変更と引き継ぎに使います。

この記事でわかること

  • TypeScriptで確かめられることと、型だけでは確かめられないこと
  • 型推論の使い方と、any・unknown・型アサーションの違い
  • APIやフォームから届く値を実行時に検証する書き方と確認の例
  • JavaScriptからの段階移行と、tsconfigの主な設定の役割
  • 型チェック・テスト・CIの確認と、変更・引き継ぎで残す記録

TypeScriptのメリットと限界:保守で何が変わるか

TypeScriptを使うと、引数・返り値・プロパティの使い方の不整合を、コードを実行する前に確認しやすくなります。TypeScriptは静的な型チェックを行う言語で、型の情報はエディタの補完やエラーの表示にも使われます(TypeScript Handbook:The Basics、確認日:2026年10月21日)。一方で、型の注釈は実行時の動作を変えず、変換後のJavaScriptからは取り除かれます。型チェックで分かる範囲は、検査の対象になっているファイルと設定に左右されます。また、型チェックは実行速度の向上や、不具合がなくなることを保証するものではありません。

JavaScriptのままでも、エディタの補完やJSDocのコメントを使って型を確認する進め方があり、TypeScriptを採用するために、一括で書き換える必要はありません。変更を確かめるときは、次のように複数の方法を組み合わせます。

表は横にスクロールできます →

▼ 変更時に組み合わせる確認
確認の方法確かめることそれだけでは確かめられないこと
静的な型チェック検査の対象となるコードの型の整合性、宣言と使い方の不整合実際に届く入力、権限、業務のルールや計算の正しさ
実行時の入力検証届いた値の形、項目、許可する値や範囲項目の意味やほかのデータとの整合、実装していない認可などの条件
テスト・受入の確認決めた条件での処理結果、異常系、業務上の期待結果書いていない条件や、確かめていない環境での動作
lint・整形設定した規則や表記の一貫性型チェック、業務のテスト、実際の入力の検査

型推論と型設計:any・unknown・型アサーション

すべての変数に型を書く必要はありません。型推論を活かし、関数の入出力やモジュールの境界など、意味を共有する箇所に必要な型を書きます。TypeScriptは初期値や使われ方から型を推論し、推論と同じ型をわざわざ書かなくてもよいとされています(Type Inference、Everyday Types)。

  • any:その値に関する型チェックを止めます。使った箇所とそこから広がる処理の検査は弱まりますが、プロジェクト全体の型チェックがすべて無意味になるわけではありません。使う場合は、理由と範囲、見直す条件を残します。
  • unknown:中身を確かめるまで、プロパティの参照などを許さない型です。unknownと書いても検証の処理が作られるわけではなく、typeofなどの条件で実際に確かめる必要があります(Narrowing)。
  • 型アサーション(as)と非null指定(!):コンパイル時に取り除かれ、実行時の検査や変換は行いません(Everyday Types、いずれも確認日:2026年10月21日)。根拠がないまま型エラーを消すために使いません。

APIでやり取りするデータと画面で使うデータは、役割に応じて型を分けます。型の管理元は、API仕様(OpenAPIなど)から生成する、型を手で一元管理する、検証の定義から型を得るといった方法から、更新の担当と同期の方法で選びます。生成した型があるだけでは、届いた値を検証したことにはなりません。API仕様の合意と変更の管理は、APIファースト開発の記事で扱っています。

API・フォームの実行時検証:型定義だけで入力を信用しない

API・フォーム・保存済みのJSONなどから届く値は、型定義があっても、実行時に検査してから内部の処理へ渡します。型の注釈は、届いた値を変えることも確かめることもないためです。画面側のチェックは、サーバー側の入力検証や権限の確認の代わりにはなりません。利用者へのエラーの伝え方は、業務システムのUI/UX改善の記事で扱っています。

次は、注文の要約を受け取る処理を想定した説明用の例です。1行目の型の宣言は実行時には残らず、実際に値を確かめているのはif文の条件です。

order-summary.ts(説明用の例)

type OrderSummary = { orderId: string; totalYen: number };

function parseOrderSummary(input: unknown): OrderSummary | null {
  if (typeof input !== "object" || input === null) return null;
  if (
    !("orderId" in input) || typeof input.orderId !== "string" ||
    input.orderId.trim() === "" ||
    !("totalYen" in input) || typeof input.totalYen !== "number" ||
    !Number.isSafeInteger(input.totalYen) || input.totalYen < 0
  ) return null;
  return { orderId: input.orderId, totalYen: input.totalYen };
}

この例では、注文IDを「空白だけではない文字列」、合計を「0以上の安全な整数(円単位)」と定めています。0円も受け付け、文字列の"1200"を数値へ自動で変換しません。返すのはorderIdとtotalYenの2項目だけで、ほかの項目が含まれていても採用しません。条件に合わない場合はnullを返すため、呼び出す側はnullを確認し、表示や保存などの後続の処理へ進まないようにします。API通信やJSONの構文解析の失敗は、この関数の前で別に扱います。

表は横にスクロールできます →

▼ 入力と確認結果の例
入力の例戻り値理由
{ orderId: "O-1", totalYen: 1200 }OrderSummary例で定めた項目と値の条件に合う
{ orderId: "O-1", totalYen: "1200" }null合計が数値ではない(文字列を変換しない)
{ totalYen: 1200 }null注文IDがない
nullnullオブジェクトではない
{ orderId: "O-1", totalYen: -1 }null例で許容する範囲(0以上)の外

合計が0の { orderId: "O-1", totalYen: 0 } は条件に合うため、そのまま返します。この関数は、合計が明細と一致するか、注文の所有者や閲覧の権限、文字列の長さ、保存の成否などは検査しません。それらは業務と運用の条件に応じて別に実装・テストします。型が合うことと、情報が正しいことは同じではありません。既存のスキーマ定義や検証ライブラリを使う方法もあり、手書きの検証が唯一の方法ではありません。

JavaScriptからTypeScriptへの段階移行

移行は一括で書き換えず、今の動作とテストを確かめてから、対象と厳格さを少しずつ広げます。最初に、変更が多い処理、障害の影響、外部からの入力、今のテスト、依存するライブラリ、ビルドと実行の仕組みを確認します。公式の移行ガイドも、設定を整えてから1ファイルずつ移し、厳しい検査は段階的に有効にする流れを示しています(Migrating from JavaScript、確認日:2026年10月21日)。

  1. 今の動作と検査の対象を記録し、確かめられている業務と、まだ確かめられない業務を分ける。
  2. JavaScriptとTypeScriptを共存させる範囲、JavaScript側のチェック、変換と実行を担うツールを決める。
  3. 小さな変更の単位で型と入力の条件を整理し、テストとレビューで動作の差を確かめる。
  4. 例外を記録し、対象と厳格さを広げる条件、担当、戻す方法を決める。新規の開発ではstrictを基本の候補とし、既存の環境では対象の範囲とエラーの解消計画を合意する。

次の表は、既存のWebアプリを改修するときに、対象と未確認の事項を記録する例です。前の節と同じ注文の要約を扱うアプリを想定した説明用の設定で、実際の調査結果や、すべての現場に当てはまる優先順位ではありません。

表は横にスクロールできます →

▼ 改修の対象と未確認事項の記入例
対象現在の扱い次の確認担当と完了の条件
注文の要約を受け取る処理型の定義はある。実際の入力の検証は未確認正常、項目の欠落、異なる型、0円、負数を受け取ったときの動作を確かめるAPI担当。許可する値と、不正なときに表示・保存へ進まないことをレビューで確認する
既存JavaScriptの入力画面移行の候補。checkJsの影響と既存のテストの範囲は未確認対象のファイルを区切り、型エラーと今の動作を確かめるフロント担当。指摘への対応と残す例外を記録し、操作と送信を確認する
CIの型チェック実行の記録はある。対象のファイルと、失敗時に止まる条件は未確認使う設定・除外・失敗時の扱いと、必要なマージの条件を照らし合わせる保守担当。対象の範囲と結果、未対応の事項、次の確認日を残す

一部のファイルで型チェックが通ったことを、全体の移行の完了や実行時の安全性と読み替えません。未確認の事項は0件と報告せず、担当と次の確認日を残します。

tsconfigの設定:strictと追加の確認項目

tsconfigの設定は、ほかのプロジェクトの設定をそのまま貼り付けず、一つずつ役割と影響を確かめて選びます。主な設定の役割は次のとおりです。

表は横にスクロールできます →

▼ tsconfigの主な設定と注意点
設定確認すること導入時の注意
allowJsJavaScriptのファイルを対象に含め、TypeScriptと共存させるJavaScript側の検査と、ビルド・実行の環境の対応は別に確かめる
checkJs対象のJavaScriptにも型エラーを報告するファイルごとの // @ts-check やJSDocから始める方法もある
strict厳格な検査の系列をまとめて有効にする個別の設定での上書きと、TypeScriptの版による違いを確かめる。実行時の保証ではない
noImplicitAny型を推論できず、暗黙のanyになる箇所などを指摘するstrictの系列。すべての変数への型の記述や、明示的なanyの禁止ではない
strictNullChecksnullとundefinedを区別して扱うstrictの系列。型の情報と実際の入力が異なる場合は、別に検査する
noUncheckedIndexedAccessインデックス(添字)でのアクセスなどで、値がない可能性を型に含めるstrictとは別に検討する。非null指定で型エラーだけを消して回避しない
exactOptionalPropertyTypesプロパティがないことと、明示的なundefinedを区別するstrictとは別に検討する。undefinedを許すなら型に明示する。既存の更新処理への影響を確かめる

strictは厳格な検査の系列をまとめて有効にし、個別の設定で一部を外すこともできます。TypeScriptの更新で新しい検査が加わり、型エラーが増える場合もあります。noImplicitAnyとstrictNullChecksはこの系列に含まれますが、noUncheckedIndexedAccessとexactOptionalPropertyTypesは含まれないため、既存のコードへの影響を確かめてから別に判断します。exactOptionalPropertyTypesを有効にしても、colorThemeOverride?: "dark" | "light" | undefined のようにundefinedを型に含めれば、明示的なundefinedは許されます。出典はTSConfig ReferenceのallowJs・checkJs・strict・noImplicitAny・strictNullChecks・noUncheckedIndexedAccess・exactOptionalPropertyTypesの各ページです(いずれも確認日:2026年10月21日)。ここで示すのは役割の説明で、特定のサイトの設定値をおすすめの完成形とするものではありません。

型チェック・テスト・CIで変更を確かめる

変更を確かめるときは、型チェック、入力検証の異常系、業務の期待結果、画面の操作の確認を組み合わせ、何を確かめ、何が残っているかを記録します。型の名前が同じでも入力の仕様が変わることがあり、依存ライブラリの更新でも型と動作を別に確かめます。

  • 設定ファイルを指定して型チェックだけを行う例は tsc --noEmit -p tsconfig.json です。ファイル名を直接指定する実行は、この設定を使う実行とは異なります。TypeScript 5.9系ではtsconfig.jsonを読み込まずに進み、6.0ではtsconfig.jsonがあるディレクトリでファイル名を指定するとエラー(TS5112)になります。プロジェクトの設定に沿って確認する場合は、-pで設定ファイルを指定します(tsc CLI Options・TypeScript 6.0のリリースノート、確認日:2026年10月21日)。
  • noEmitは、tscが変換結果を出力しない指定で、変換をBabelやswcなど別のツールに任せる構成で使われます。noEmitOnErrorは、tscが出力する構成で、型エラーがあるときに出力を止める別の設定です(noEmit・noEmitOnError、いずれも確認日:2026年10月21日)。変換を別のツールが担う場合、型エラーで公開が止まるかは別に確かめます。すべての構成に両方を加える必要はありません。
  • lintと整形、型チェック、テストは目的が異なります。CIにコマンドを書いたことだけで、マージやデプロイが止まるとは限らないため、必要なチェックと失敗時の扱いを確かめます。
  • 型の管理元、API仕様の変更と更新の担当、受け取る値の検証の条件も、レビューの対象にします。

フロントエンドの保守・運用:変更と引き継ぎの記録

変更と引き継ぎでは、何を確かめ、何が未確認で、誰が次に確認するかを記録として残します。残す記録の例は次のとおりです。

  • 変更の対象と対象外
  • 型と検証の定義の管理元、更新の担当
  • 再現する操作と入力の例
  • 実行したチェックと結果
  • anyやasを残す理由と範囲、見直す条件
  • 未確認の事項の担当と、次の確認日
  • 公開後の確認と、戻す方法

仕様とコードのどちらを直すかがはっきりしない場合は、業務で期待する結果を確かめてから判断します。サイト全体の構成や更新の仕組みは、モダンWeb開発の構成判断で扱っています。

TypeScript導入・運用のチェックリストとFAQ

導入や改修を始める前に、分かる範囲で次の点を確認します。すべてに当てはまっても、不具合がないことが保証されるわけではありません。未確認の項目は、担当と確認の時期を決めて残します。

社内や外部に相談するときは、変更時に困っている処理、APIやフォームの入力、今のテストと保守の体制について、分かる範囲をまとめておくと整理を進めやすくなります。型エラーが多い段階やテストがない段階でも、ご相談いただけます。ソースコードや機密の資料、認証情報を相談フォームに貼っていただく必要はありません。

押さえておきたい点

TypeScriptで保守性を高めるうえで大切なのは、型を書くこと自体よりも、型で確かめられることと、実行時の検証やテストで確かめることを分け、何が未確認かを記録しながら変更を進めることです。対象と厳格さを少しずつ広げると、移行の途中でも変更の影響を確かめやすくなります。

自社の状況を確認する

  • □ 困っている変更と影響する業務、今回の対象と対象外を整理した
  • □ 型チェックの対象ファイル、設定、実行方法を確認した
  • □ 型推論で足りる箇所と、入出力の型を共有する箇所を分けた
  • □ APIやフォームなどから届く値を確かめる場所と条件を決めた
  • □ 不正な値、項目の欠落、null、0などの扱いを確認した
  • □ 型の定義・生成・入力検証の管理元と、更新の担当を決めた
  • □ anyやasなどの例外の理由・範囲・見直す条件を残した
  • □ 型チェックと業務のテストの結果、残る確認を分けて記録した
  • □ CIで必要なチェックと、失敗時の扱いを確認した
  • □ 移行と公開の単位、確認の担当、戻す方法と引き継ぐ記録を決めた

よくある質問

Q. TypeScriptを導入すれば、バグはなくなりますか?

なくなるわけではありません。型チェックは、検査の対象となるコードの宣言と使い方の不整合を見つけやすくしますが、実際に届く入力、業務の計算の正しさ、権限などは確かめません。実行時の入力検証やテスト、受入の確認と組み合わせます。

Q. すべての変数に型を書く必要はありますか?

その必要はありません。TypeScriptは初期値や使われ方から型を推論します。関数の入出力やモジュールの境界など、意味を共有する箇所に必要な型を書きます。noImplicitAnyは、推論できずに暗黙のanyになる箇所などを指摘する設定で、すべての変数への型の記述を求めるものではありません。

Q. 既存のJavaScriptを、すべて書き換える必要はありますか?

その必要はありません。allowJsでJavaScriptとTypeScriptを共存させ、checkJsやファイルごとの// @ts-checkでJavaScript側のチェックを始める方法もあります。今の動作とテストを確かめたうえで、対象と厳格さを段階的に広げます。期間や費用は対象の範囲によって変わります。

Q. APIの生成型やasがあれば、入力の検証は不要ですか?

不要にはなりません。型の情報と実行時の検査は別です。asは実行時の検査や変換を行わず、生成した型も届いた値を確かめるものではありません。使っている生成の仕組みが検証の処理も作るかを確認し、作らない場合は実行時の検証を別に用意します。

Q. 型エラーが多い段階やテストがない段階でも、相談できますか?

はい、ご相談いただけます。変更時に困っている処理、APIやフォームの入力、今のテストと保守の体制について、分かる範囲から整理します。ソースコードや機密の資料、認証情報を相談フォームに貼っていただく必要はありません。

変更が不安なコードから、改修と保守の範囲を整理します。

変更時に困る処理、APIやフォームの入力、現在のテストと保守体制をもとに、改修・テスト・引き継ぎの支援内容をご確認ください。初回相談で対象と支援範囲を確認します。

システム改修・保守の支援内容を見る

この分野の全体像

モダンWeb開発の構成判断:Next.jsとヘッドレスCMSをどう組み合わせるか

この分野の全体像と判断の順序をまとめた記事です。

全体像を読む

IT課題を、
優先順位から整理します。

Malakeは外部IT責任者として、現状の確認から実装・運用まで支援します。