TypeScript型システムベストプラクティス
TypeScript 実践テクニック集 2024 — 型安全を高める10のパターン
any を使わずに型安全なコードを書くための実践的なパターンを紹介。Template Literal Types・Conditional Types・Mapped Types など、中〜上級者向けのテクニックをサンプルコードとともに解説します。
はじめに
any に頼らず型安全なコードを書くための実践的なパターンを10個紹介します。TypeScript の型システムを使いこなすことで、バグを事前に防ぎ、リファクタリングも安全に行えるようになります。
1. Template Literal Types
文字列の型を組み合わせて新しい型を生成できます。
type EventName = 'click' | 'focus' | 'blur'
type Handler = `on${Capitalize<EventName>}`
// "onClick" | "onFocus" | "onBlur"
2. Conditional Types
型レベルの条件分岐で、引数の型に応じて戻り値の型を変えられます。
type Flatten<T> = T extends Array<infer U> ? U : T
type Str = Flatten<string[]> // string
type Num = Flatten<number> // number
3. Mapped Types で readonly を外す
type Mutable<T> = {
-readonly [K in keyof T]: T[K]
}
4. satisfies 演算子
型チェックしつつ、推論した型を保持したい場合に有効です。
const palette = {
red: [255, 0, 0],
green: '#00ff00',
} satisfies Record<string, string | number[]>
// palette.red は number[] として推論される(string | number[] ではなく)
5. const assertion
配列・オブジェクトリテラルをより狭い型にします。
const DIRECTIONS = ['north', 'south', 'east', 'west'] as const
type Direction = typeof DIRECTIONS[number]
// "north" | "south" | "east" | "west"
6. Discriminated Union
type フィールドで型を絞り込む王道パターンです。
type Result<T> =
| { status: 'success'; data: T }
| { status: 'error'; message: string }
function handle<T>(result: Result<T>) {
if (result.status === 'success') {
console.log(result.data) // T 型
} else {
console.log(result.message) // string 型
}
}
7. infer で型を取り出す
type ReturnType<T> = T extends (...args: unknown[]) => infer R ? R : never
type Fn = () => { id: number; name: string }
type R = ReturnType<Fn> // { id: number; name: string }
8. Exclude / Extract
Union 型から特定の型を除外・抽出します。
type Status = 'pending' | 'active' | 'inactive' | 'deleted'
type ActiveStatus = Exclude<Status, 'deleted' | 'inactive'>
// "pending" | "active"
9. Record でオブジェクト型を作る
type Color = 'red' | 'green' | 'blue'
const hex: Record<Color, string> = {
red: '#ff0000',
green: '#00ff00',
blue: '#0000ff',
}
10. 型ガードを自作する
function isString(value: unknown): value is string {
return typeof value === 'string'
}
const values: unknown[] = ['hello', 42, 'world']
const strings = values.filter(isString) // string[]
まとめ
これらのパターンを組み合わせることで、any に頼らない堅牢な型定義が書けるようになります。最初は難しく感じますが、実際のコードで少しずつ使っていくと自然に身についていきます。