判別共用体

共通の判別子(discriminator)プロパティを持つ型の合併。TypeScriptではtypeプロパティによる絞り込みが一般的。代数的データ型の一種。

基本形

type Result<T, E> =
  | { success: true; value: T }
  | { success: false; error: E };

function handle(result: Result<User, Error>) {
  if (result.success) {
    // result.value は T 型に絞り込まれる
  } else {
    // result.error は E 型に絞り込まれる
  }
}

Make Illegal States Unrepresentable

Make Illegal States Unrepresentableの実現手段として有効:

// 弱い構造 — 不正状態が表現可能
type Order = {
  status: string;
  paidAt: Date | null;
  shippedAt: Date | null;
};

// 強い構造 — 不正状態がコンパイル時に排除
type Order =
  | { status: "draft" }
  | { status: "paid"; paidAt: Date }
  | { status: "shipped"; paidAt: Date; shippedAt: Date };

判別子の二面性

判別子としてのtype属性は、文脈によって異なる性質を持つ:

性質 説明 結合の種類
命令的フラグ 処理分岐を指示 制御結合(悪い)
識別子 データの属性を宣言 データ結合(良い)

例:命令的フラグ(悪い)

// バックエンドが実装詳細を操作している
{ type: "use_legacy_algorithm", data: ... }

例:識別子(良い)

// データの種類を宣言しているだけ
{ type: "user_created", userId: "123" }

TypeScriptの構造的型付けの問題

TypeScriptは構造的型付けのため、制御フラグと識別子の区別が型レベルで曖昧になりやすい。

解決策:

境界での使い方

腐敗防止層で判別共用体を使い、入り口で一度だけ分岐を吸収するのが良いパターン。

関連