ジェネリクス
TypeScript
型パラメーターと制約
ジェネリクスの基本
型パラメーターで再利用可能な型を定義
// ジェネリック関数
function identity<T>(value: T): T {
return value;
}
identity<string>('hello'); // 'hello'
identity(42); // 型推論: number
// 配列の最初の要素
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
first([1, 2, 3]); // number | undefined
first(['a', 'b']); // string | undefined
// ジェネリックインターフェース
interface Repository<T> {
findById(id: number): Promise<T>;
findAll(): Promise<T[]>;
save(entity: T): Promise<T>;
delete(id: number): Promise<void>;
}
// ジェネリッククラス
class Stack<T> {
private items: T[] = [];
push(item: T): void { this.items.push(item); }
pop(): T | undefined { return this.items.pop(); }
peek(): T | undefined { return this.items.at(-1); }
isEmpty(): boolean { return this.items.length === 0; }
}型制約
extends で型パラメーターを制限する
// extends による制約
function getLength<T extends { length: number }>(val: T): number {
return val.length;
}
getLength('hello'); // 5
getLength([1, 2, 3]); // 3
// getLength(42); // ❌ エラー: numberはlengthを持たない
// keyof 制約
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, 'email'); // ❌ エラー
// 複数の制約
function merge<T extends object, U extends object>(a: T, b: U): T & U {
return { ...a, ...b };
}
// デフォルト型パラメーター
interface ApiResponse<T = unknown> {
data: T;
status: number;
message: string;
}
type UserResponse = ApiResponse<User>; // data は User 型
type RawResponse = ApiResponse; // data は unknown 型実用ジェネリックパターン
ReturnType、Parameters、infer など
// infer — 型の推論
type ReturnType<T extends (...args: any) => any> =
T extends (...args: any) => infer R ? R : never;
type Unpacked<T> =
T extends Array<infer Item> ? Item :
T extends Promise<infer Resolved> ? Resolved :
T;
type A = Unpacked<string[]>; // string
type B = Unpacked<Promise<number>>; // number
// 非同期関数の戻り値型
async function fetchUser(): Promise<User> { /* ... */ return user; }
type FetchResult = Awaited<ReturnType<typeof fetchUser>>; // User
// 条件型 + ジェネリクス
type NonNullable<T> = T extends null | undefined ? never : T;
type Flatten<T> = T extends Array<infer Item> ? Item : T;
// Mapped Type + ジェネリクス
type Nullable<T> = { [K in keyof T]: T[K] | null };
type Optional<T> = { [K in keyof T]?: T[K] };
type Stringify<T> = { [K in keyof T]: string };