T extends U ジェネリック制約
最終更新:2026-10-22
T extends U ジェネリック制約
制約(extends)は型パラメータに「範囲を定め」ます。<T extends HasId> は「T は少なくとも id: number を持つ」と約束します。制約の内側では T の公開メンバーに安心してアクセスでき、制約の外側(string を渡すなど)はコンパイル時に拒否されます。any より安全で、具体型より柔軟です。
| グループ | ジェネリクス |
|---|---|
| 種類 | 構文 |
| strict モード | 不要 |
ℹ️ 説明 エディタは TypeScript を JavaScript にトランスパイルして実行します(型チェックなし)。型チェック結果は各サンプルの出力を参照してください。
📝 構文
interface HasId {
id: number;
}
function findById<T extends HasId>(items: T[], id: number): T | undefined {
return items.find((item) => item.id === id);
}
⚙️ パラメータ
| T extends HasId | 制約:実引数の型は HasId と互換(少なくとも id: number を含む)でなければなりません |
|---|---|
| T | undefined | 戻り値型は実引数の正確な形状を保持します。どんな形状の配列を渡せば、同じ形状の要素を取り返します |
戻り値:制約なしのジェネリックと同じです——実引数の正確な型は保持されます。違いは、関数本体の中で T の使えるメンバーが増える点です。
▶ サンプル
下のコードを編集して「試す」を押すと、トランスパイル実行結果を確認できます:
出力:
Desk
見つかりません
(トランスパイル後の実行出力。products の要素に余分なフィールドがあっても構いません——構造的型付けは制約が要求するメンバーだけを検査します)
💡 ポイント
ℹ️ 説明 制約は「完全一致」を求めません。{ id: 1, name: "Lamp", price: 59 } の余分なフィールドは互換性に影響しません。構造的型付けは制約が要求するメンバーが揃っているかだけを見ます。
💡 ヒント インラインの制約は中間インターフェースを省きます。function sumLengths<T extends { length: number }>(a: T, b: T) は「length があればよい」と直接記述できます。複雑になったときだけインターフェースに切り出します。
⚠️ 注意 制約が与えるのは「下限」です。T extends HasId は id の存在しか保証せず、item.name はコンパイラの目にはまだ存在しません——name: string も追加で制約しない限り。
🏷️ 関連ジェネリクス
💡 関連ケース
ケースは今後追加予定です。
📚 関連チュートリアル
❓ よくある質問
Q 制約とジェネリックのデフォルト値は同時に使えますか?
A 使えますし、よく組み合わせます:<T extends HasId = User> ——未指定ならデフォルトの User、指定する場合は HasId を満たす必要があります。デフォルト値は制約の範囲内でなければなりません。
Q 「いくつかのリテラルのいずれか」に制約するには?
A リテラルのユニオンを使います。function set<K extends "light" | "dark">(theme: K)。K は具体的なリテラルに絞り込まれ、範囲外の値はコンパイルエラーになります。
Q 複数の型パラメータが互いに制約し合うには?
A 後のパラメータに前のパラメータを参照させます。<K extends keyof T> ——K の取りうる範囲が T で決まります。これが keyof パターンの核心で、キー名がオブジェクトと実際に一致することを保証します。