0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

今回は、TypeScriptの条件型についてまとめます。

条件型とは

TypeScriptの条件型とは、型システムに条件分岐を導入するものです。

下記の構文で表現され、
TU に割り当て可能であれば X、そうでなければ Y 」という意味になります。

T extends U ? X : Y

例えば下記の場合、T に入る値が string の場合に true、そうでない場合に false を返します。

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

type Result1 = IsString<"hello">; // true
type Result2 = IsString<123>; // false

分配条件型

分配条件型は、T がユニオン型である場合に、ユニオン型の各要素に対して条件型が個別に適用される仕組みです、

type Distributive<T> = T extends string ? "String" : "Other";

type Result = Distributive<"hello" | 42 | true>;
// Result = "Other" | "String"

ユニオン型から特定の型だけを抽出することもできます。

type ExtractString<T> = T extends string ? T : never;
type OnlyStrings = ExtractString<"hello" | 42 | "world">;
// OnlyStrings = "hello" | "world"

Inferキーワード

条件型には、ジェネリック型をインラインで宣言する独自構文があり、それが infer です。

下記の構文で使用され、
TArray 型に一致する場合、infer U を使用して配列の要素型を U として推論しています。
それ以外の場合は never が返されます。

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

下記の例では配列の要素型を抽出しています。

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

type StringArray = ElementType<string[]>; // StringArray = string
type NumberArray = ElementType<number[]>; // NumberArray = number
type NonArray = ElementType<boolean>;    // NonArray = never

関数の引数型や戻り値の型を抽出することもできます。

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

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

type Result = ReturnType<MyFunction>; // Result = string
type Arg = ArgumentType<MyFunction>; // Arg = number

組み込みの条件型

TypeScriptには、型を操作するための便利な組み込みユーティリティ型がいくつか用意されています。

Exclude<T, U>

Exclude<T, U> は、T には含まれているが U には含まれていない型を計算します。

構文
type Exclude<T, U> = T extends U ? never : T;
type Union = "a" | "b" | "c";
type WithoutA = Exclude<Union, "a">;
// WithoutA = "b" | "c"

Extract<T, U>

Extract<T, U> は、T には含まれている型のうち、U に割り当てできるものを計算します。

構文
type Extract<T, U> = T extends U ? T : never;
type Union = "a" | "b" | "c";
type OnlyA = Extract<Union, "a">;
// OnlyA = "a"

NonNullable<T>

NonNullable<T> は、nullundefined を型から除外するために使用します。

構文
type NonNullable<T> = T extends null | undefined ? never : T;
type NullableType = string | null | undefined;
type NonNull = NonNullable<NullableType>;
// NonNull = string

ReturnType<F>

ReturnType<F> は、関数の戻り値の型を計算します。
F は型を取得したい関数を表しています。

構文
type ReturnType<F> = F extends (...args: any[]) => infer R ? R : any;
function getUser() {
  return { name: "John", age: 30 };
}
type User = ReturnType<typeof getUser>;
// User = { name: string; age: number }

InstanceType<C>

InstanceType<C> は、クラスのインスタンス型を計算します。
C は型を取得したいクラス名を表しています。

構文
type InstanceType<C extends new (...args: any) => any> = C extends new (...args: any) => infer R ? R : never;
class Person {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

type PersonInstance = InstanceType<typeof Person>;
// PersonInstance = Person

おわりに

条件型をしようすることで柔軟にカスタマイズでき、
コードも簡潔に記述できるので非常に便利だと思いました。

それでは。

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?