← TypeScriptページに戻る
💡

TypeScriptのサンプルコード

文法解説で学んだ知識を組み合わせた、難易度が段階的に上がる3本の実践的なサンプルプログラムです。①型定義を使った小規模アプリ、②ジェネリクスを使ったデータ構造とアルゴリズム、③型ガード・判別可能なUnion型を使った高度な型の活用、の順に解説します。

サンプル1:型定義を使ったタスク管理アプリ

interface・リテラル型のユニオン・readonly/オプショナルプロパティを組み合わせた、シンプルなタスク管理プログラムです。 優先度(priority)はリテラル型のユニオンで表現し、許可されていない値は代入できません。 classにタスクの追加・完了・優先度順の一覧表示をまとめています。

SAMPLE PROGRAM
type Priority = "low" | "medium" | "high";

interface Task {
  readonly id: number;     // 一度発行したら変更しない
  title: string;
  priority: Priority;
  done: boolean;
  dueDate?: string;        // 期限は省略可能
}

class TaskManager {
  private tasks: Task[] = [];
  private nextId = 1;

  add(title: string, priority: Priority, dueDate?: string): Task {
    const task: Task = {
      id: this.nextId++,
      title,
      priority,
      done: false,
      dueDate,
    };
    this.tasks.push(task);
    return task;
  }

  complete(id: number): boolean {
    const target = this.tasks.find((t) => t.id === id);
    if (!target) return false;
    target.done = true;
    return true;
  }

  // 優先度順(high > medium > low)に並べた未完了タスク一覧
  listPending(): Task[] {
    const order: Record<Priority, number> = { high: 0, medium: 1, low: 2 };
    return this.tasks
      .filter((t) => !t.done)
      .sort((a, b) => order[a.priority] - order[b.priority]);
  }
}

const manager = new TaskManager();
manager.add("設計書レビュー", "high", "2026-07-10");
manager.add("備品発注", "low");
manager.add("テストコード作成", "medium");

manager.complete(2);

for (const task of manager.listPending()) {
  console.log(`[${task.priority}] ${task.title}${task.dueDate ? " (期限: " + task.dueDate + ")" : ""}`);
}
// [high] 設計書レビュー (期限: 2026-07-10)
// [medium] テストコード作成

サンプル2:ジェネリックなキューを使ったグラフの幅優先探索(BFS)

ジェネリクスで実装した汎用的なキュー(FIFO:先入れ先出し)を使い、グラフの最短経路をたどる幅優先探索(BFS)を実装します。 キューへのenqueue/dequeueはいずれも計算量 O(1)、BFS全体の計算量は頂点数V・辺数Eに対して O(V + E) です。

SAMPLE PROGRAM
class Queue<T> {
  private items: T[] = [];

  enqueue(item: T): void {   // O(1)
    this.items.push(item);
  }

  dequeue(): T | undefined { // O(1)(配列先頭のshiftはO(n)になるため、内部的にはindex管理でも良い)
    return this.items.shift();
  }

  isEmpty(): boolean {
    return this.items.length === 0;
  }
}

// 隣接リストで表現したグラフ
type Graph = Map<string, string[]>;

function bfs(graph: Graph, start: string, goal: string): string[] | null {
  const queue = new Queue<string[]>();  // 経路(パス)をキューに積む
  const visited = new Set<string>([start]);
  queue.enqueue([start]);

  while (!queue.isEmpty()) {
    const path = queue.dequeue();
    if (!path) continue;

    const node = path[path.length - 1];
    if (node === goal) return path; // 目的地に到達

    const neighbors = graph.get(node) ?? [];
    for (const next of neighbors) {
      if (!visited.has(next)) {
        visited.add(next);
        queue.enqueue([...path, next]);
      }
    }
  }
  return null; // 到達不可能
}

const graph: Graph = new Map([
  ["A", ["B", "C"]],
  ["B", ["D"]],
  ["C", ["D"]],
  ["D", ["E"]],
]);

console.log(bfs(graph, "A", "E")); // ["A", "B", "D", "E"] または ["A", "C", "D", "E"]

サンプル3:判別可能なUnion型と型ガードを使った図形の面積計算

「判別可能なユニオン型(Discriminated Union)」は、共通のリテラル型プロパティ(ここではkind)で種類を判別するパターンです。 switch文のdefault節で戻り値をnever型の変数に代入することで、将来図形の種類を追加した際に分岐漏れがあればコンパイルエラーで検知できる「網羅性チェック」を行っています。

SAMPLE PROGRAM
interface Circle {
  kind: "circle";
  radius: number;
}
interface Rectangle {
  kind: "rectangle";
  width: number;
  height: number;
}
interface Triangle {
  kind: "triangle";
  base: number;
  height: number;
}

type Shape = Circle | Rectangle | Triangle;

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;      // ここではCircleに絞り込まれている
    case "rectangle":
      return shape.width * shape.height;       // ここではRectangleに絞り込まれている
    case "triangle":
      return (shape.base * shape.height) / 2;  // ここではTriangleに絞り込まれている
    default: {
      // 全パターンを処理済みならshapeはnever型になる(網羅性チェック)
      const exhaustiveCheck: never = shape;
      throw new Error(`未対応の図形です: ${exhaustiveCheck}`);
    }
  }
}

const shapes: Shape[] = [
  { kind: "circle", radius: 2 },
  { kind: "rectangle", width: 3, height: 4 },
  { kind: "triangle", base: 5, height: 6 },
];

for (const s of shapes) {
  console.log(`${s.kind}: ${area(s).toFixed(2)}`);
}
// circle: 12.57
// rectangle: 12.00
// triangle: 15.00

クイズに挑戦する →