TypeScriptにおけるUnion型とIntersection型は、柔軟な型定義を可能にする重要な機能です。この記事では、実践的な例を交えながら、これらの型の使い方を詳しく解説します。

Union型の基本と活用法

Union型(`|`)は、複数の型のいずれかを表現できる型です。以下のような場合に特に有用です:

// 基本的なUnion型の例
type StringOrNumber = string | number;

const value: StringOrNumber = "hello"; // OK
const value2: StringOrNumber = 42;     // OK

実践的なUnion型の使用例

// APIのレスポース状態を表現する
type ApiResponse = {
  status: "success" | "error";
  data?: any;
  error?: string;
};

// ユーザーの役割を定義
type UserRole = "admin" | "user" | "guest";

function handleUser(role: UserRole) {
  switch (role) {
    case "admin":
      console.log("管理者権限です");
      break;
    case "user":
      console.log("一般ユーザーです");
      break;
    case "guest":
      console.log("ゲストユーザーです");
      break;
  }
}

Intersection型の基本と活用法

Intersection型(`&`)は、複数の型を組み合わせて新しい型を作成します。

// 基本的なIntersection型の例
type Person = {
  name: string;
  age: number;
};

type Employee = {
  companyId: string;
  role: string;
};

type EmployeePerson = Person & Employee;

const worker: EmployeePerson = {
  name: "山田太郎",
  age: 30,
  companyId: "E123",
  role: "engineer"
};

実践的なIntersection型の使用例

// ベースとなる共通の型
type BaseProps = {
  className?: string;
  style?: React.CSSProperties;
};

// ボタンコンポーネントの独自のプロプス
type ButtonProps = {
  onClick: () => void;
  label: string;
} & BaseProps;

// 実装例
const Button: React.FC<ButtonProps> = ({ onClick, label, className, style }) => {
  return (
    <button
      onClick={onClick}
      className={className}
      style={style}
    >
      {label}
    </button>
  );
};

高度な型の組み合わせ

Union型とIntersection型を組み合わせることで、より複雑な型定義が可能になります:

// 様々な形式のユーザー入力を処理する例
type ValidationSuccess = {
  isValid: true;
  value: string;
};

type ValidationError = {
  isValid: false;
  error: string;
};

type ValidationResult = ValidationSuccess | ValidationError;

function validate(input: string): ValidationResult {
  if (input.length > 0) {
    return {
      isValid: true,
      value: input
    };
  } else {
    return {
      isValid: false,
      error: "入力が空です"
    };
  }
}

ベストプラクティスとTips

1. 型の命名規則を統一する

type UserData = {
  id: string;
  name: string;
};

type UserActions = {
  update: () => void;
  delete: () => void;
};

type User = UserData & UserActions;

2. 型の再利用を意識する

// 共通のプロパティを持つベース型
type WithTimestamp = {
  createdAt: Date;
  updatedAt: Date;
};

// 様々な型に適用
type Post = {
  title: string;
  content: string;
} & WithTimestamp;

type Comment = {
  text: string;
  authorId: string;
} & WithTimestamp;

3. 条件付き型との組み合わせ

type NonNullable<T> = T extends null | undefined ? never : T;
type NumberOrString = string | number | null;
type SafeValue = NonNullable<NumberOrString>; // string | number

これらの型システムを適切に活用することで、より安全で保守性の高いTypeScriptコードを書くことができます。特に大規模なアプリケーション開発では、これらの型の組み合わせが重要な役割を果たします。