TypeScript / LESSON 17 / TS17

TypeScript:tsconfigと厳格モード

1学習の目的

2基礎解説

ここまで null の扱いや暗黙の any が厳しくチェックされてきました。これらはすべて設定で切り替えられます。設定ファイルが tsconfig.json です。

設定防ぐもの
noImplicitAny型を書き忘れた引数function f(x)
strictNullChecksnull/undefined の見落としs.length(sがnullかも)
noUnusedLocals使っていない変数消し忘れたコード
strict上記をまとめて有効化推奨設定
✅ 覚えるべき重要ポイント
  1. "strict": true が最重要。これ1つで noImplicitAnystrictNullChecks など複数の厳格チェックがまとめて有効になる。新規プロジェクトでは必ず有効にする
  2. strictNullChecks を切ると、TS06・TS08で学んだ null 安全が失われるconst s: string = null; が通るようになり、実行時エラーの温床になる。
  3. noImplicitAny は「型の書き忘れ」を防ぐ(TS05)。これが無いと、引数が黙って any になり、型チェックが素通りする。
  4. target出力するJavaScriptのバージョン"ES2020" なら最近の書き方がそのまま出力され、古い指定なら変換される。
  5. 既存プロジェクトへの導入は段階的に。いきなり strict にすると大量のエラーが出るので、1つずつ有効化して直していくのが現実的。

現場使用例:プロジェクト立ち上げ時の設定、既存コードのTypeScript化、チームでの品質基準の統一。設定はチーム全員に等しく効く「自動レビュー」になる

// tsconfig.json の基本形
{
  "compilerOptions": {
    "target": "ES2020",           // 出力するJSのバージョン
    "module": "commonjs",         // モジュールの形式
    "strict": true,               // ⭐ 厳格チェックをまとめて有効化
    "noUnusedLocals": true,       // 未使用の変数を検出
    "noImplicitReturns": true,    // return漏れを検出
    "outDir": "./dist"            // 出力先
  },
  "include": ["src/**/*"]         // 対象のファイル
}

// ▼ strict が無効だと、これらが全部通ってしまう

// noImplicitAny が無効なら…
function bad(x) {          // x は暗黙の any
  return x.foo.bar;        // 何も警告されない
}

// strictNullChecks が無効なら…
const s: string = null;    // 通ってしまう
console.log(s.length);     // 実行時に落ちる

// ✅ strict: true なら、どちらも書いた時点でエラーになる

3基本ドリル(10問)

TS17-D01 TypeScript の設定ファイル名はどれか。
A. package.json B. tsconfig.json C. config.ts D. tsc.json
選択★☆☆無料
期待される結果

解答 == B

ヒント

TypeScript の設定を意味するファイル名。

模範解答
B
解説

プロジェクトのルートに置く。このファイルがあると、tsc コマンドが自動的に設定を読み込む。

TS17-D02 "strict": true の効果として正しいものはどれか。
A. 実行速度が上がる B. 複数の厳格チェックがまとめて有効になる C. エラーを無視する D. 型注釈が不要になる
選択★☆☆無料
期待される結果

解答 == B

ヒント

strict は複数の設定をまとめたもの。

模範解答
B
解説

noImplicitAny・strictNullChecks など7つ以上の設定が一度に有効になる。個別に書く必要がなく、新規プロジェクトではこれ1つで十分。

TS17-D03 厳格モードで通るように、引数に型を付けた関数 double を定義し、double(21) の結果を出力せよ。 コーディング★☆☆無料
期待される結果

出力 == 42

ヒント

引数の型を省略すると noImplicitAny でエラーになる。

模範解答
function double(n: number): number {
  return n * 2;
}

console.log(double(21));
解説

引数の型を書くのは noImplicitAny のため(TS05)。この設定を切れば省略できるが、型チェックの意味が失われる。

TS17-D04 strictNullChecks を無効にすると、const s: string = null; はどうなるか。
A. エラーになる B. 通ってしまう C. 空文字になる D. undefined になる
選択★☆☆無料
期待される結果

解答 == B

ヒント

この設定が null と型を区別している。

模範解答
B
解説

TS06・TS08で学んだ null 安全がすべて失われるs.length が実行時に落ちるまで気づけなくなる。

TS17-D05 target の設定は何を指定するものか。
A. 対象のファイル B. 出力するJavaScriptのバージョン C. エラーの厳しさ D. 出力先フォルダ
選択★☆☆無料
期待される結果

解答 == B

ヒント

変換先のJavaScriptに関する設定。

模範解答
B
解説

古いブラウザ向けなら ES5、モダンな環境なら ES2020 以上を指定する。新しい書き方が使えるかどうかに影響する。

TS17-D06 strictNullChecks が有効な環境で安全に動くよう、null を返しうる関数の結果を確認してから使うコードを書け。「該当なし」と出力すること。 コーディング★★☆無料
期待される結果

出力 == 該当なし

ヒント

戻り値の型を string | null にし、?? で既定値を指定する。

模範解答
function find(id: number): string | null {
  return id === 1 ? "ノートPC" : null;
}

console.log(find(99) ?? "該当なし");
解説

strictNullChecks があるから、この確認を強制される。無効なら find(99).length と書けてしまい、実行時に落ちる。

TS17-D07 noUnusedLocals は何を検出するか。
A. 型の間違い B. 使われていない変数 C. null の見落とし D. return の書き忘れ
選択★★☆無料
期待される結果

解答 == B

ヒント

unused は「使われていない」という意味。

模範解答
B
解説

消し忘れたコードや、書きかけの変数を見つけてくれる。コードの掃除に役立つが、開発中は煩わしいこともあるので、プロジェクトによって判断が分かれる。

TS17-D08 既存の大きなJavaScriptプロジェクトをTypeScript化するとき、推奨されるのはどれか。
A. いきなり strict を有効にする B. 設定を1つずつ有効にして段階的に直す C. すべて any にする D. 型を一切書かない
選択★★☆無料
期待される結果

解答 == B

ヒント

いきなり全部有効にすると何が起きるか。

模範解答
B
解説

いきなり strict にすると数千件のエラーが出ることもあるnoImplicitAny から始めて1つずつ潰していくのが現実的な移行手順。

TS17-D09 noImplicitReturns が有効でも通るよう、すべての分岐で return する関数 judge を書け(点数60以上なら「合格」、それ未満は「不合格」)。80点と50点で試し、2行出力すること。 コーディング★★☆無料
期待される結果

出力2行。合格 / 不合格

ヒント

if の中だけで return すると、else の経路で return が無くなる。

模範解答
function judge(score: number): string {
  if (score >= 60) {
    return "合格";
  }
  return "不合格";
}

console.log(judge(80));
console.log(judge(50));
解説

すべての経路で値を返しているif の中だけに return を書くと、条件を満たさない場合に undefined が返り、TS04で学んだエラーになる。

TS17-D10 厳格モードで通るよう、catch のエラーを型ガードで確認してからメッセージを出力するコードを書け(「処理に失敗しました」と出力)。 コーディング★★☆無料
期待される結果

出力 == 処理に失敗しました

ヒント

catch (e) の e は unknown。instanceof Error で確認する(TS14)。

模範解答
try {
  throw new Error("処理に失敗しました");
} catch (e) {
  console.log(e instanceof Error ? e.message : "不明なエラー");
}
解説

useUnknownInCatchVariables という設定によるもの。strict に含まれており、これが無ければ e は any になって確認せずに使えてしまう。

4実践シナリオ(5問)

TS17-S01 【厳格モードで通るコード】次の3つの条件をすべて満たす関数 calcTotal を書け。①引数に型がある ②すべての分岐で return する ③null の可能性を確認する。
仕様:価格(number)と割引率(number | null)を受け取り、割引率が null なら定価、そうでなければ割引後の価格(四捨五入)を返す。20000円で割引率0.1と null の2通りを試すこと。
コーディング★★☆無料
期待される結果

出力2行。18000 / 20000

ヒント

割引率が null かどうかを確認してから計算する。

模範解答
function calcTotal(price: number, rate: number | null): number {
  if (rate === null) {
    return price;
  }
  return Math.round(price * (1 - rate));
}

console.log(calcTotal(20000, 0.1));
console.log(calcTotal(20000, null));
解説

3つの厳格チェックをすべて満たしている。引数に型があり、両方の経路で return し、null を確認してから計算に使っている。

TS17-S02 【null 安全の実践】商品配列から検索し、見つからない場合も安全に処理する関数を書け。found の可能性を型で表現し、2通り(見つかる/見つからない)で「ノートPC:128,000円」「該当なし」と2行出力すること。 コーディング★★☆無料
期待される結果

出力2行が完全一致

ヒント

find の結果は undefined になりうる。?? や条件分岐で対処する。

模範解答
type Product = { name: string; price: number };

const items: Product[] = [{ name: "ノートPC", price: 128000 }];

function describe(name: string): string {
  const found = items.find((i) => i.name === name);

  if (!found) {
    return "該当なし";
  }

  return `${found.name}:${found.price.toLocaleString()}円`;
}

console.log(describe("ノートPC"));
console.log(describe("存在しない商品"));
解説

strictNullChecks があるので、found の確認を省略できない。この設定が無ければ found.name と直接書けてしまい、実行時に落ちる。

TS17-S03 【設定の効果を確かめる】暗黙の any を避けるため、すべての引数と戻り値に型を付けた集計関数 summarize を書け。商品配列を受け取り、「3件・合計139,700円」の形式の文字列を返すこと。 コーディング★★☆無料
期待される結果

出力 == 3件・合計139,700円

ヒント

引数の型は Product[]、戻り値は string。reduce のコールバックの引数は推論されるので省略可。

模範解答
type Product = { name: string; price: number };

function summarize(items: Product[]): string {
  const total: number = items.reduce((sum, i) => sum + i.price, 0);
  return `${items.length}件・合計${total.toLocaleString()}円`;
}

const products: Product[] = [
  { name: "ノートPC", price: 128000 },
  { name: "マウス", price: 3200 },
  { name: "キーボード", price: 8500 },
];

console.log(summarize(products));
解説

reduce の中の sum と i は推論されるので型注釈は不要。関数の入口と出口だけ型を明示すれば、内部は推論に任せられる(TS05)。

TS17-S04 【段階的な型付け】any を使わずに外部データを扱う関数 parse を書け。unknown で受け取り、検証してから商品として扱い、失敗なら null を返すこと。正常なデータと不正なデータの2通りで「ノートPC」「不正なデータ」と2行出力すること。 コーディング★★★無料
期待される結果

出力2行。ノートPC / 不正なデータ

ヒント

TS15で学んだ型ガードを使う。any を1つも使わずに書く。

模範解答
type Product = { name: string; price: number };

function parse(v: unknown): Product | null {
  if (typeof v !== "object" || v === null) {
    return null;
  }

  const o = v as Record<string, unknown>;

  if (typeof o.name !== "string" || typeof o.price !== "number") {
    return null;
  }

  return { name: o.name, price: o.price };
}

for (const input of [{ name: "ノートPC", price: 128000 }, { name: 123 }]) {
  const p = parse(input);
  console.log(p ? p.name : "不正なデータ");
}
解説

any を1つも使わずに外部データを扱えている。厳格モードは「any を書かせない」ための設定であり、代わりに unknown と型ガードで安全性を担保する。

TS17-S05 【網羅性と厳格性の組み合わせ】ステータス("未発送"|"発送済"|"配達完了")を受け取り、次の状態を返す関数を書け。すべての分岐で return し、never による網羅性チェックも入れること。3つのステータスで試し、3行出力すること(最終状態は「完了」)。 コーディング★★★無料
期待される結果

出力3行。発送済 / 配達完了 / 完了

ヒント

switch で分岐し、default に never チェックを入れる(TS16)。

模範解答
type Status = "未発送" | "発送済" | "配達完了";

function nextStatus(current: Status): string {
  switch (current) {
    case "未発送":
      return "発送済";
    case "発送済":
      return "配達完了";
    case "配達完了":
      return "完了";
    default: {
      const exhaustive: never = current;
      return exhaustive;
    }
  }
}

for (const s of ["未発送", "発送済", "配達完了"] as Status[]) {
  console.log(nextStatus(s));
}
解説

noImplicitReturns と never チェックが両方効いている。すべての経路で return し、かつすべてのステータスを処理していることが、二重に保証されている。

5仕上げ課題

TS17-FINAL 【厳格モード対応の在庫管理】strict モードのすべての制約を満たす在庫管理プログラムを書け。

満たすべき条件
① すべての関数の引数に型注釈がある(noImplicitAny)
② null / undefined の可能性を必ず確認する(strictNullChecks)
③ すべての分岐で return する(noImplicitReturns)
④ catch のエラーは型を確認してから使う
any を1つも使わない

実装する内容
・型:Item = { id: number; name: string; stock: number | null }
stockLabel(item) … 在庫がnullなら「未登録」、0なら「品切れ」、10未満なら「残りわずか」、それ以外は「在庫あり」
findItem(id) … 見つからなければ undefined を返す
reduceStock(id, qty) … 在庫を減らす。商品が無い/在庫未登録/在庫不足なら例外を投げる

データ:ノートPC(id:1,在庫5)、マウス(id:2,在庫null)、サンプル(id:3,在庫0)

期待される出力(6行)
ノートPC:残りわずか
マウス:未登録
サンプル:品切れ
---
減算成功:残り3個
エラー:在庫が未登録です
期待される結果

出力6行が完全一致

ヒント

stockLabel は null チェックを最初に行う。reduceStock は3つの失敗パターンで例外を投げ、catch では instanceof Error で確認する。ノートPCから2個減らし、マウス(在庫null)から1個減らそうとして失敗させる。

模範解答
type Item = {
  id: number;
  name: string;
  stock: number | null;
};

const items: Item[] = [
  { id: 1, name: "ノートPC", stock: 5 },
  { id: 2, name: "マウス", stock: null },
  { id: 3, name: "サンプル", stock: 0 },
];

function stockLabel(item: Item): string {
  if (item.stock === null) {
    return "未登録";
  }
  if (item.stock === 0) {
    return "品切れ";
  }
  if (item.stock < 10) {
    return "残りわずか";
  }
  return "在庫あり";
}

function findItem(id: number): Item | undefined {
  return items.find((i) => i.id === id);
}

function reduceStock(id: number, qty: number): number {
  const item = findItem(id);

  if (!item) {
    throw new Error("商品が見つかりません");
  }
  if (item.stock === null) {
    throw new Error("在庫が未登録です");
  }
  if (item.stock < qty) {
    throw new Error("在庫が不足しています");
  }

  item.stock -= qty;
  return item.stock;
}

for (const item of items) {
  console.log(`${item.name}:${stockLabel(item)}`);
}

console.log("---");

try {
  const remaining = reduceStock(1, 2);
  console.log(`減算成功:残り${remaining}個`);
} catch (e) {
  console.log(`エラー:${e instanceof Error ? e.message : "不明"}`);
}

try {
  reduceStock(2, 1);
  console.log("減算成功");
} catch (e) {
  console.log(`エラー:${e instanceof Error ? e.message : "不明"}`);
}
解説

このコードは、厳格モードのすべての制約を満たしている。そして重要なのは、制約を守ることが、そのまま堅牢なコードになっていることだ。

stock: number | null という型が、「在庫が未登録の商品がある」という業務上の現実を表している。strictNullChecks があるおかげで、item.stock - qty と直接書けば止められる。「未登録」と「0個」を混同するバグが、構造的に起きない。

findItemItem | undefined を返すのも同じだ。if (!item) の確認を書かなければコンパイルが通らないので、「見つからなかった場合」を考え忘れることがない

catch (e)e instanceof Error も、strict に含まれる設定によるものだ。JavaScriptでは文字列でも数値でも throw できるため、Error だと決めつけてはいけない。

厳格モードは「面倒な制約」ではなく、「バグを事前に潰す仕組み」だ。設定を1行書くだけで、チーム全員のコードに同じ品質基準が適用される。人間のレビューでは見落とすものを、機械が確実に指摘してくれる。

次章はいよいよ最終回。ここまでの17章すべてを統合して、型安全な在庫管理システムを完成させる。