TypeScriptのConditional Types(条件付き型)は、型の条件分岐を可能にする強力な機能です。この記事では、Conditional Typesの基本的な使い方から実践的な活用方法まで、わかりやすく解説します。

Conditional Typesとは

Conditional Typesは、TypeScriptで型の条件分岐を行うための機能です。三項演算子に似た構文を使用して、型レベルでif-else文のような条件分岐を実現できます。

type CheckType<T> = T extends string ? 'yes' : 'no';

基本的な使い方

単純な条件分岐

最も基本的な使用例を見てみましょう:

type IsString<T> = T extends string ? true : false;

// 使用例
type Result1 = IsString<'hello'>; // true
type Result2 = IsString<123>;     // false

複数の条件分岐

ネストした条件分岐も可能です:

type TypeName<T> = 
  T extends string ? 'string' :
  T extends number ? 'number' :
  T extends boolean ? 'boolean' :
  'unknown';

// 使用例
type Result3 = TypeName<'test'>;  // 'string'
type Result4 = TypeName<42>;      // 'number'

実践的な活用例

オプショナルプロパティの型定義

type NonNullable<T> = T extends null | undefined ? never : T;

// 使用例
type Optional<T> = {
  [P in keyof T]: NonNullable<T[P]>;
};

関数の戻り値型の制御

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

// 使用例
function getMessage() {
  return 'Hello World';
}

type MessageType = ReturnType<typeof getMessage>; // string

infer キーワードの活用

`infer`キーワードを使用すると、条件型の中で型を推論できます:

type ArrayElementType<T> = T extends Array<infer U> ? U : never;

// 使用例
type StringArray = string[];
type ElementType = ArrayElementType<StringArray>; // string

よくある使用パターン

ユニオン型の絞り込み

type FilterString<T> = T extends string ? T : never;

// 使用例
type Mixed = string | number | boolean;
type OnlyString = FilterString<Mixed>; // string

オブジェクト型の変換

type ToReadonly<T> = {
  readonly [P in keyof T]: T[P];
};

// 使用例
interface User {
  name: string;
  age: number;
}

type ReadonlyUser = ToReadonly<User>;

Conditional Typesのベストプラクティス

1. 型の命名は明確で説明的にする

2. 複雑な条件は小さな型に分割する

3. コメントで型の目的を説明する

まとめ

Conditional Typesは、TypeScriptの型システムをより柔軟に活用するための重要な機能です。基本的な条件分岐から複雑な型の変換まで、様々なシナリオで活用できます。型の安全性を保ちながら、より表現力豊かなコードを書くことが可能になります。

実践的な使用例を通じて、Conditional Typesの理解を深めることで、より堅牢なTypeScriptアプリケーションの開発が可能になります。