T extends U ? X : Y 条件型
最終更新:2026-10-22
T extends U ? X : Y 条件型
条件型は型に「選択問題」を解かせます:T extends U ? X : Y ——条件を満たせば X、さもなければ Y を選びます。実行時の三項判定を型レベルに持ち込み、ジェネリックと組み合わせれば入力の型に応じて変わる戻り値型が書けます。
| グループ | ジェネリクス |
|---|---|
| 種類 | 構文 |
| strict モード | 不要 |
ℹ️ 説明 エディタは TypeScript を JavaScript にトランスパイルして実行します(型チェックなし)。型チェック結果は各サンプルの出力を参照してください。
📝 構文
type Wrapped<T> = T extends string
? { kind: "str"; value: T }
: { kind: "num"; value: number };
type A = Wrapped<string>; // { kind: "str"; value: string }
type B = Wrapped<number>; // { kind: "num"; value: number }
// ユニオン型は分配的に展開される(分配条件型)
type ToArray<T> = T extends unknown ? T[] : never;
⚙️ パラメータ
| T extends U | 条件判断:構造的に互換なら真の分岐を取ります |
|---|---|
| ? X : Y | 2つの分岐:どちらも完全な型式で、条件をさらにネストできます |
戻り値:条件型は純粋な型レベルの演算で、実行時コードを生成しません。結果はジェネリック実引数が extends を満たすかどうかで決まります。
▶ サンプル
下のコードを編集して「試す」を押すと、トランスパイル実行結果を確認できます:
出力:
{"kind":"str","value":"hi"}
{"kind":"num","value":7}
(トランスパイル後の実行出力。wrap(true) はコンパイルエラーになります——boolean を受け付けるオーバーロードが存在しないためです)
💡 ポイント
ℹ️ 説明 裸の型パラメータはユニオン型に出会うと「分配」します。ToArray<string | number> は (string | number)[] ではなく string[] | number[] になります——これが条件型の分配的性質であり、Exclude の実装原理でもあります。
💡 ヒント never は条件型では「ろ過して除去」の合図です。type NonNull<T> = T extends null | undefined ? never : T は、分配のあと null/undefined のメンバーを自動的に取り除きます。
⚠️ 注意 条件型が3層を超えると可読性が急落します。マップ型やインデックスアクセスで解決できるなら条件型を使わないでください。ネストするときは中間の type エイリアスで段階に分けましょう。
🏷️ 関連ジェネリクス
💡 関連ケース
ケースは今後追加予定です。
📚 関連チュートリアル
❓ よくある質問
Q 条件型と関数オーバーロードはどう使い分けますか?
A 型ロジックが単純(1〜2分岐)なら条件型で1つのシグネチャにまとめます。分岐が多い、またはリテラル単位の正確さが要るならオーバーロードのほうが直感的です。両者は混用できます(例もそうしています)。
Q T extends string が string | number にも「成立」するのはなぜですか?
A 分配が働いています。ユニオンがばらされて1つずつ判定され、その後に統合されます。全体をまとめて判定したい(分配を避けたい)ときは [T] extends [string] というタプルで包む書き方を使います。
Q 条件型を関数パラメータに使えますか?
A 使えますが注意が必要です。パラメータ位置の条件型は呼び出し側の推論を微妙にします。よくあるパターンは、パラメータはジェネリックにし、戻り値型を条件型で連動させる形です。