実践LESSON 07

この教材で学ぶこと 型・union・narrowing・runtime validationで変更を安全にします。

TypeScript入門

対象読者: JavaScriptの基本を理解し、規模が大きくても変更しやすいコードを書きたい人。

この教材でできるようになること

  • TypeScriptが実行前に行う型検査の役割を説明できる
  • object、union、narrowingを使って状態を表せる
  • unknownを安全に検証できる
  • compiler optionのstrictが重要な理由を説明できる

1. TypeScriptはJavaScriptへ型検査を加える

TypeScriptの型は、実行前に不整合を発見するための情報です。ブラウザやNode.jsで動く時点では通常JavaScriptへ変換されています。

function formatProgress(done: number, total: number): string {
  if (total <= 0) throw new Error("total must be positive");
  return `${done}/${total}`;
}

formatProgress("3", 5); // 型エラー

2. objectの形を定義する

type Lesson = {
  id: string;
  title: string;
  level: "beginner" | "intermediate" | "advanced";
  completed: boolean;
};

function nextLesson(lessons: Lesson[]): Lesson | undefined {
  return lessons.find((lesson) => !lesson.completed);
}

文字列を何でも許可せずunionで候補を限定すると、表記揺れを型検査で防げます。

3. discriminated unionで状態を表す

type LoadState =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; lessons: Lesson[] }
  | { status: "error"; message: string };

function message(state: LoadState): string {
  switch (state.status) {
    case "idle": return "待機中";
    case "loading": return "読み込み中";
    case "success": return `${state.lessons.length}件`;
    case "error": return state.message;
  }
}

statusを確認すると、TypeScriptはそのbranchで利用可能なpropertyを絞り込みます。

4. 外部入力はunknownから始める

API responseやJSONは、型注釈を書くだけでは実行時に検証されません。

function isLesson(value: unknown): value is Lesson {
  if (typeof value !== "object" || value === null) return false;
  const candidate = value as Record<string, unknown>;
  return typeof candidate.id === "string"
    && typeof candidate.title === "string"
    && typeof candidate.completed === "boolean"
    && ["beginner", "intermediate", "advanced"].includes(String(candidate.level));
}

型の外側にある入力境界では、runtime validationが必要です。

5. anyを避ける

anyはその値に対する型検査を事実上止めます。分からない値にはunknownを使い、調べてから操作します。

function errorMessage(error: unknown): string {
  return error instanceof Error ? error.message : "Unknown error";
}

6. strictから始める

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true
  }
}

既存の大規模JavaScriptへ段階導入する事情がなければ、最初からstrictを有効にするほうが安全です。

演習: API responseを検証する

次のJSONをunknownとして受け取り、Lesson[]であることを検証する関数を作ってください。

[
  { "id": "ts-01", "title": "TypeScript入門", "level": "beginner", "completed": false }
]

配列か、全要素がisLessonを満たすかを確認し、不正なら理由を含む例外を投げます。

理解チェック

  • compile-timeの型とruntimeの値を区別できる
  • unionとnarrowingで状態を表現できる
  • unknownを検証してから利用できる
  • anyが型安全性を失わせる理由を説明できる

公式資料

次に読む

テストとデバッグで、型検査だけでは保証できない振る舞いを確かめます。