ジェネリクス:T extends と制約
ジェネリック関数とインターフェースを書き、extends で型パラメーターを制約し、柔軟な API のためにジェネリックのデフォルトを使います。
「ジェネリクス:T extends と制約」はCoddyKit上の無料Frontend Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはFrontend Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Frontend Academyコースには全4レッスンが含まれています。
ジェネリクスとは
ジェネリクスを使うと、型安全性を保ちながら、複数の型で動作する関数、クラス、インターフェースを記述できます。型ごとに別々の関数を書く代わりに、型変数でパラメーター化した1つのジェネリック関数を書きます。
単純なジェネリック関数
型パラメーター T は山かっこ内で宣言します。TypeScript は引数の型から T を推論するため、呼び出し側で明示的なアノテーションを付ける必要はありません。
function identity<T>(value: T): T {
return value;
}
identity(42); // T is inferred as number, returns number
identity('hello'); // T inferred as string
identity<boolean>(true); // explicitジェネリックインターフェースと型
ジェネリクスでインターフェースや型をパラメーター化すると、再利用可能なデータ構造を表現できます。
interface Box<T> {
value: T;
label?: string;
}
const numBox: Box<number> = { value: 42 };
const strBox: Box<string> = { value: 'hello', label: 'greeting' };extends — ジェネリック型の制約
T extends SomeType を使うと、T に指定できる型を制限できます。この関数は、制約を満たす型だけを受け取ります。
function getLength<T extends { length: number }>(item: T): number {
return item.length; // safe: T is guaranteed to have length
}
getLength('hello'); // 5
getLength([1, 2, 3]); // 3
getLength({ length: 7 }); // 7
// getLength(42); // Error: number has no lengthkeyof とジェネリック制約
keyof T は、T のプロパティキーのユニオン型を生成します。ジェネリクスと組み合わせることで、型安全なプロパティアクセスが可能になります。
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: 'Alice', age: 30 };
getProperty(user, 'name'); // string
getProperty(user, 'age'); // number
// getProperty(user, 'foo'); // Errorジェネリックのデフォルト
T = DefaultType を使うと、ジェネリックパラメーターにデフォルトの型を指定できます。適切なデフォルト値がある一方で、呼び出し側から上書きできる場合に使用します。
interface Paginated<T = unknown> {
items: T[];
total: number;
page: number;
}
const rawPage: Paginated = { items: [], total: 0, page: 1 };
const typedPage: Paginated<User> = { items: [], total: 0, page: 1 };複数の型パラメーター
関数には、互いに独立した複数の型パラメーターを指定できます。
function zip<A, B>(arrA: A[], arrB: B[]): Array<[A, B]> {
return arrA.map((a, i) => [a, arrB[i]]);
}
zip([1, 2, 3], ['a', 'b', 'c']);
// [[1,'a'], [2,'b'], [3,'c']]ジェネリッククラス
クラスもジェネリックにできます。スタック、キュー、observable store などのデータ構造でよく使われます。
class Stack<T> {
private items: T[] = [];
push(item: T) { this.items.push(item); }
pop(): T | undefined { return this.items.pop(); }
peek(): T | undefined { return this.items.at(-1); }
get size() { return this.items.length; }
}
const stack = new Stack<number>();
stack.push(1);
stack.push(2);
stack.pop(); // 2非同期ジェネリック関数
ジェネリックな非同期関数は、型付けされた API 呼び出しでよく使われます。
async function fetchJson<T>(url: string): Promise<T> {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json() as Promise<T>;
}
const users = await fetchJson<User[]>('/api/users');
const profile = await fetchJson<UserProfile>('/api/me');条件型での infer
条件型内の infer キーワードは、パターンから型を抽出します。ライブラリコードで、関数の戻り値の型や配列の要素型を抽出するために使用します。
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type ElementType<T> = T extends Array<infer E> ? E : never;
type Fn = () => { name: string };
type Result = ReturnType<Fn>; // { name: string }ジェネリクスを使う場面
次のような場合にジェネリクスを使用します:1) 同じロジックを複数の型に適用する場合、2) 入力型と出力型の関係が必要な場合、3) 再利用可能なデータ構造やユーティリティを作成する場合です。必要以上にジェネリクスを使わないでください。ユースケースが1つだけなら、具体的な型のほうが明確です。
確認問題
T extends { length: number } という制約は何を保証しますか?
まとめ:ジェネリクス
ジェネリクスは型をパラメーター化し、1つの関数、クラス、インターフェースを複数の型で使用できるようにします。T extends SomeType は制約を追加します。keyof T はプロパティキーのユニオン型を生成します。T = Default のようなジェネリックのデフォルトを指定できます。infer は条件型から型を抽出します。再利用可能な型付きユーティリティやデータ構造にはジェネリクスを使用します。
よくある質問
「ジェネリクス:T extends と制約」レッスンは無料ですか?
はい。「ジェネリクス:T extends と制約」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Frontend Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Frontend Academyコースには全4レッスンが含まれています。
「ジェネリクス:T extends と制約」で何を学びますか?
ジェネリック関数とインターフェースを書き、extends で型パラメーターを制約し、柔軟な API のためにジェネリックのデフォルトを使います。 ブラウザで直接実行するハンズオンコードでFrontend Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Frontend Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのFrontend Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「ジェネリクス:T extends と制約」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このFrontend Academyレッスンでコードを書いて実行できますか?
はい。すべてのFrontend Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ジェネリクス:T extends と制約
- ユーティリティ型:Partial・Required・Pick・Omit
- Mapped Types と Conditional Types
- 型の絞り込み:typeof・instanceof・判別可能なユニオン