kind 判別可能ユニオン
最終更新:2026-10-22
kind 判別可能ユニオン
判別可能ユニオン(tagged union とも呼ばれます)は、共通の判別フィールド(status、kind など)で一連の型を結び付け、各メンバーの判別フィールドに互いに異なるリテラル値を取らせます。判別フィールドを switch すると、TS が自動的に対応するメンバーへナローイングます。業務モデリングで最も実用的なユニオン型の使い方です。
| グループ | ナローイングとアサーション |
|---|---|
| 種類 | 型 |
| strict モード | 不要 |
ℹ️ 説明 エディタは TypeScript を JavaScript にトランスパイルして実行します(型チェックなし)。型チェック結果は各サンプルの出力を参照してください。
📝 構文
type Result<T> =
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; message: string };
function handle<T>(res: Result<T>) {
switch (res.status) {
case "loading": /* res: data なし */ break;
case "success": res.data; break; // success メンバーにナローイング
case "error": res.message; break;
}
}
⚙️ パラメータ
| discriminant | 判別フィールド。各メンバーが必ずこのフィールドを持ち、値は互いに異なるリテラル型("loading" / "success" / "error" など)でなければなりません |
|---|
戻り値:戻り値はありません。判別可能ユニオンは型レベルのモデリング手段であり、switch/if による判別フィールドの比較をきっかけに、コンパイル時にナローイングが行われます。
▶ サンプル
下のコードを編集して「試す」を押すと、トランスパイル実行結果を確認できます:
出力:
loading…
got 3 items
error: timeout
(トランスパイル後の実行出力。success 分岐で res.data が型チェックを通るのは、判別フィールドによるナローイングのおかげです。tsc が静的に保証し、実行時に見えるのは値だけです)
💡 ポイント
ℹ️ 説明 判別フィールドの名前に制限はなく、type、kind、status、state、tag がよく使われます。重要なのはメンバーごとに異なるリテラル値を取ることで、TS が一意に識別できるようにすることです。
⚠️ 注意 判別フィールドは必須のリテラル型でなければなりません。"success" のようなリテラルではなく string と書いたり、オプショナルにしたりすると識別力が失われ、ナローイングが効かなくなります。
💡 ヒント 判別可能ユニオンと網羅性チェックは黄金の組み合わせです。すべての判別値を switch しておけば、メンバーを追加したときにコンパイラが漏れた分岐をすべて指摘します(assertNever と併用。exhaustive-checks の項目を参照)。
🏷️ 関連ナローイングとアサーション
💡 関連ケース
ケースは今後追加予定です。
📚 関連チュートリアル
❓ よくある質問
Q 判別可能ユニオンと普通のユニオン型の違いは何ですか?
A 普通のユニオンは typeof/in のような汎用チェックでしか絞り込めません。判別可能ユニオンはリテラルの判別フィールドを持つため、1つのフィールドを switch するだけで正確に1つのメンバーへ到達でき、網羅性チェックも可能です。判別フィールドを設計できるなら優先して使いましょう。
Q 判別フィールドはオブジェクトの内側にネストできますか?
A できます。TS はネストしたプロパティ(配列の要素でさえも)に対する判別ナローイングをサポートします。たとえば res.meta.state のように。ただしネストが深いほど可読性が落ちるため、慣例では判別フィールドはトップレベルに置きます。
Q 数値列挙を判別値として使えますか?
A 使えます。列挙メンバー(数値列挙を含む)はリテラル型なので、メンバーごとに異なる列挙値を取れば判別可能ユニオンになります。デバッグ時の読みやすさは文字列列挙の方が数値列挙に勝ります。