Blog 一覧に戻る
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 に頼らない堅牢な型定義が書けるようになります。最初は難しく感じますが、実際のコードで少しずつ使っていくと自然に身についていきます。