TypeScriptのジェネリクスは、型を引数として受け取る仕組みです。「同じロジックを複数の型で安全に再利用」できる強力な機能ですが、初学者にとってはとっつきにくい部分でもあります。本記事では、ジェネリクスを図解的に理解できるよう解説します。
ジェネリクスとは
関数や型に「型変数」を持たせ、使う側が具体的な型を指定できる仕組みです。Tがよく使われますが、任意の名前で構いません。
function identity<T>(value: T): T {
return value;
}
identity<string>('hello'); // T = string
identity<number>(42); // T = number
identity('hello'); // 推論で T = string
配列を扱う例
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
const n = first([1, 2, 3]); // number | undefined
const s = first(['a', 'b']); // string | undefined
制約(extends)
「Tはこの形を持つ型に限る」と制約をかけられます。
function getId<T extends { id: number }>(obj: T): number {
return obj.id;
}
getId({ id: 1, name: 'A' }); // OK
// getId({ name: 'A' }); // エラー:idが無い
複数の型変数
function merge<A, B>(a: A, b: B): A & B {
return { ...a, ...b };
}
const merged = merge({ name: 'A' }, { age: 30 });
// { name: string; age: number }
クラスでのジェネリクス
class Box<T> {
constructor(public value: T) {}
}
const numBox = new Box(42); // Box<number>
const strBox = new Box('hello'); // Box<string>
条件付き型と組み合わせ
type IsString<T> = T extends string ? 'yes' : 'no';
type A = IsString<'hello'>; // 'yes'
type B = IsString<42>; // 'no'
keyof と組み合わせる
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { id: 1, name: 'A' };
const n = getProp(user, 'id'); // number
const s = getProp(user, 'name'); // string
実務でよく出るパターン
- API呼び出しのレスポンス型:
fetch<T>(url: string): Promise<T> - Reactフック:
useState<User>()useReducer<Reducer<State, Action>>() - コレクション操作:map・filter・reduce
- ファクトリ・ビルダー:型に応じて返り値を変える
まとめ
ジェネリクスは「型を後から決められる関数・型」を作る仕組みです。identity関数→配列→制約→keyofの順で段階的に学べば、難しさは大きく減ります。実務では「型を保ったまま再利用できる」恩恵が大きく、避けて通れないテーマです。