ジェネリクス

型をパラメータ化し、型安全性を保ちながら汎用的なコードを書く仕組み

TypeScript型システム

ジェネリクスとは

ジェネリクス (Generics) は、型をパラメータ化し、型安全性を保ちながら汎用的なコードを書く仕組みである。any を使わずに、様々な型で動作する関数やクラスを定義できる。

基本

// ❌ any: 型安全性がない
function first(arr: any[]): any { return arr[0]; }

// ✅ ジェネリクス: 型安全
function first<T>(arr: T[]): T | undefined { return arr[0]; }

first([1, 2, 3]);       // number
first(['a', 'b', 'c']); // string

制約 (extends)

// T は length プロパティを持つ型に制限
function longest<T extends { length: number }>(a: T, b: T): T {
  return a.length >= b.length ? a : b;
}

longest('hello', 'world');  // ✅ string は length を持つ
longest([1, 2], [1, 2, 3]); // ✅ 配列は length を持つ
longest(1, 2);               // ❌ number は length を持たない

複数の型パラメータ

function map<T, U>(arr: T[], fn: (item: T) => U): U[] {
  return arr.map(fn);
}

map([1, 2, 3], n => n.toString()); // string[]

ジェネリクスの実用例

API レスポンスの型

interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

async function fetchApi<T>(url: string): Promise<ApiResponse<T>> {
  const res = await fetch(url);
  return res.json();
}

const { data } = await fetchApi<User[]>('/api/users');
// data の型: User[]

DynamoDB のリポジトリ

interface Repository<T> {
  findById(id: string): Promise<T | null>;
  save(item: T): Promise<void>;
}

class DynamoDBRepository<T> implements Repository<T> {
  constructor(private tableName: string) {}
  async findById(id: string) { /* ... */ }
  async save(item: T) { /* ... */ }
}

const userRepo = new DynamoDBRepository<User>('users');
const orderRepo = new DynamoDBRepository<Order>('orders');

ユーティリティ型

説明
Partial<T> 全プロパティをオプショナルに
Required<T> 全プロパティを必須に
Pick<T, K> 指定プロパティだけ抽出
Omit<T, K> 指定プロパティを除外
Record<K, V> キーと値の型を指定したオブジェクト
type UserUpdate = Partial<Pick<User, 'name' | 'email'>>;
// { name?: string; email?: string }

ジェネリクスの理解を深めるには関連書籍が参考になる。

関連用語