TypeScript ジェネリクス入門:`<T>` の基本と型制約の書き方

スポンサーリンク

TypeScript ジェネリクス入門:<T> の基本と型制約の書き方

ジェネリクス(Generics)は、型を引数として受け取れる仕組みです。同じ処理を異なる型に対して型安全に使い回せます。


なぜジェネリクスが必要か

any を使うと型の恩恵がなくなります。

// any を使う場合:型チェックが効かない
function identity(arg: any): any {
  return arg
}

const result = identity(42)
result.toUpperCase() // 実行時エラーだが TypeScript は気づけない

ジェネリクスを使うと、型を保ったまま汎用的に書けます。

// ジェネリクスを使う場合:型が保たれる
function identity<T>(arg: T): T {
  return arg
}

const num = identity(42)       // num: number
const str = identity("hello")  // str: string

基本の書き方

関数名の後に <T> を付けて型引数を宣言します。T は慣習的な名前で、任意の名前を使えます。

function wrap<T>(value: T): { value: T } {
  return { value }
}

const wrapped = wrap("hello") // { value: string }

型引数は明示的に指定することもできます。

const result = identity<number>(42)

配列を受け取る例

function first<T>(arr: T[]): T | undefined {
  return arr[0]
}

const num = first([1, 2, 3])      // number | undefined
const str = first(["a", "b"])     // string | undefined

interface と type でのジェネリクス

// interface
interface Box<T> {
  value: T
  label: string
}

const numBox: Box<number> = { value: 42, label: "数値" }
const strBox: Box<string> = { value: "hello", label: "文字列" }

// type alias
type Pair<T, U> = {
  first: T
  second: U
}

const pair: Pair<string, number> = { first: "age", second: 30 }

型制約(extends)

型引数に制約を付けることで、使えるメソッドや型を絞れます。

// length プロパティを持つ型だけ受け付ける
function getLength<T extends { length: number }>(arg: T): number {
  return arg.length
}

getLength("hello")   // 5
getLength([1, 2, 3]) // 3
getLength(42)        // エラー:number に length はない

特定の型のサブタイプに絞ることもできます。

type Animal = { name: string }

function getName<T extends Animal>(animal: T): string {
  return animal.name
}

keyof との組み合わせ

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key]
}

const user = { name: "Alice", age: 30 }

const name = getProperty(user, "name") // string
const age  = getProperty(user, "age")  // number
getProperty(user, "email")             // エラー:存在しないキー

よく使うパターンまとめ

パターン 書き方 用途
基本 <T> 型を引数として受け取る
複数の型引数 <T, U> 2種類以上の型を扱う
型制約 <T extends 型> 使える型を絞る
keyof 制約 <K extends keyof T> オブジェクトのキーを安全に扱う
デフォルト型 <T = string> 省略時のデフォルト型を指定

TypeScript の型システム全般については「TypeScript バージョン確認:tsc version コマンドまとめ」も参照してください。