TypeScript 条件型

TypeScript の条件型は、条件に依存する型を作成する方法を提供します。これにより、型定義の柔軟性と表現力が向上し、複雑な型の関係を明確かつ簡潔にモデル化できるようになります。この記事では、TypeScript での条件型の動作について説明し、その使用例を示します。

条件型とは何ですか?

条件型を使用すると、条件に基づいて選択される型を作成できます。プログラミングの条件文に似ていますが、型レベルで動作します。条件型の基本的な構文は次のとおりです。

type ConditionalType = T extends U ? X : Y;

この構文では、

  • T はチェックされる型です。
  • U は比較対象となる型です。
  • X は、TU を拡張する場合に返される型です。
  • Y は、TU を拡張しない場合に返される型です。

条件型の基本例

以下は、指定された型が文字列であるかどうかに基づいて異なる型を返す条件型の簡単な例です。

type IsString = T extends string ? "String" : "Not a string";

type Result1 = IsString;  // Result1 is "String"
type Result2 = IsString;  // Result2 is "Not a string"

この例では、IsString は、Tstring を拡張しているかどうかを確認します。拡張している場合、結果は "String" になります。拡張していない場合は、"Not a string" になります。

ジェネリック型での条件型の使用

条件付き型をジェネリック型と組み合わせて使用​​することで、より柔軟で再利用可能な型定義を作成することもできます。たとえば、関数の戻り値の型を抽出する型は次のようになります。

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

type FunctionType = (x: number) => string;

type Result = ReturnType;  // Result is string

この例では、ReturnTypeinfer キーワードを使用して、関数型 T の戻り値の型 R を推論します。 T が関数型の場合、ReturnType が戻り値の型になります。それ以外の場合は、デフォルトで never になります。

条件型とユニオン型

条件型は、ユニオン型と組み合わせて、複数の可能な型を処理することもできます。たとえば、異なるユニオン メンバーを区別します。

type ExtractString = T extends string ? T : never;

type UnionType = string | number | boolean;

type Result = ExtractString;  // Result is string

この例では、ExtractString は、ユニオン型 UnionType から string を抽出し、結果として string が生成されます。

型マッピングによる条件型

条件付き型を型マッピングと組み合わせて、より複雑な型変換を作成できます。たとえば、型の配列をマッピングして条件付き型を適用します。

type MapArray = {
  [K in keyof T]: T[K] extends string ? T[K] : never;
};

type ArrayType = [string, number, boolean];

type MappedArray = MapArray;  // MappedArray is [string, never, never]

この例では、MapArray は配列 T の各要素をマップし、各要素に条件付き型を適用して、文字列要素のみが保持される配列を生成します。

結論

TypeScript の条件型は、柔軟で表現力豊かな型定義を作成するための強力なツールです。条件型を活用することで、開発者は複雑な型関係をモデル化し、さまざまなシナリオを処理し、TypeScript コードの型の安全性を向上させることができます。条件型を効果的に使用する方法を理解することで、堅牢で保守しやすい TypeScript コードを記述する能力が大幅に向上します。