1
1

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 の infer キーワードを深掘りする

Posted at

表紙

TypeScript の infer キーワードは、条件型の中で使用され、型を推論するために使われます。これは複雑な型を扱う際に非常に便利で、型を抽出したり変換したりするのに役立ちます。

基本的な使い方

infer キーワードは条件型の中でのみ使用でき、通常はジェネリクスと extends キーワードと組み合わせて使われます。その基本的な構文は以下のようになります。

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

ここで T extends infer U は、型 T を推論し、それを U に代入しようとすることを意味します。型の推論が成功した場合、U が推論された型となります。

次に、さまざまな型を推論する例を見てみましょう。

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

type StringType = Moment<string>; // string
type NumberType = Moment<number>; // number
type UnionType = Moment<string | number>; // string | number

interface User {
  name: string;
  age: number;
}

type UserType = Moment<User>; // User

これらの例では、Moment<T> は単に T の型を返すだけで、変換や処理は行いません。これは条件型と型推論の基本的な使い方を示すための例です。

よくある使用例

関数の戻り値の型を抽出する

関数の型がある場合、その戻り値の型を取得したいとします。その場合、次のように infer を使えます。

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

type ExampleFunction = (x: number, y: string) => boolean;
type ReturnTypeOfExampleFunction = GetReturnType<ExampleFunction>; // boolean

上記のコードでは、以下のように動作します。

  1. T extends (...args: any[]) => infer R: T が関数型であるかをチェックします。(...args: any[]) は、その関数が任意の数の引数を受け取ることを示します。
  2. infer R: T が関数型である場合、関数の戻り値の型を R として推論します。
  3. ? R : never: T が関数型なら R を返し、そうでなければ never を返します。

配列要素の型を抽出する

infer を使用して配列の要素の型を取得することもできます。

type GetArrayElementType<T> = T extends (infer U)[] ? U : never;

type Moment = string[];
type Example1Array = Array<string>;

type ElementTypeOfExampleArray = GetArrayElementType<Moment>; // string
type ElementTypeOfExample1Array = GetArrayElementType<Example1Array>; // string

ここでは、T extends (infer U)[] を使って、配列の要素型 U を推論しています。例えば、Tstring[] の場合、Ustring となります。

string[] extends (infer U)[]

重要なのは、infer は条件型の extends 句の中でのみ使用可能であり、infer で宣言された型変数は true 分岐の中でのみ有効である点です。

応用例

Promise の値の型を抽出する

Promise 型がある場合、その解決後の値の型を取得できます。

type GetPromiseValueType<T> = T extends Promise<infer U> ? U : never;

// 使用例
type ExamplePromise = Promise<number>;
type ValueTypeOfExamplePromise = GetPromiseValueType<ExamplePromise>; // number

このコードでは、次のように動作します。

  1. T extends Promise<infer U>: TPromise 型かどうかをチェックします。
  2. infer U: TPromise 型である場合、その値の型を U として推論します。
  3. ? U : never: TPromise 型なら U を返し、そうでなければ never を返します。

関数のパラメーターの型を取得する

関数のパラメーター型を取得したい場合、infer を使用できます。

type GetParameters<T> = T extends (...args: infer P) => any ? P : never;

type ExampleFunction = (a: number, b: string) => void;
type Params = GetParameters<ExampleFunction>; // [number, string]

ここでは、T extends (...args: infer P) => any によって T が関数型かを判定し、infer P で関数のパラメーターの型を推論しています。

コンストラクターのパラメーターの型を取得する

クラスのコンストラクターのパラメーター型を取得することもできます。

type ConstructorParameters<T> = T extends new (...args: infer P) => any ? P : never;

class ExampleClass {
  constructor(public a: number, public b: string) {}
}

type Params = ConstructorParameters<typeof ExampleClass>; // [number, string]

条件型での複雑な推論

条件型の中で、より複雑な推論を行うことも可能です。

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

type ExtractType<T> = T extends any[]
  ? IsArray<T>
  : T extends (...args: any[]) => any
  ? IsFunction<T>
  : T;

// 使用例
type ArrayType = ExtractType<string[]>; // string
type FunctionReturnType = ExtractType<() => number>; // number
type DefaultType = ExtractType<boolean>; // boolean

ここでの処理は以下の通りです。

type ExtractType<T> = T extends any[]
  ? IsArray<T>
  : T extends (...args: any[]) => any
  ? IsFunction<T>
  : T;
  1. T extends any[] ? IsArray<T>: T が配列型なら、要素の型を返します。
  2. T extends (...args: any[]) => any ? IsFunction<T>: T が関数型なら、戻り値の型を返します。
  3. T: それ以外の場合は T 自体を返します。

まとめ

infer キーワードは条件型の中で使用され、他の型から新しい型変数を推論するために用いられます。これにより、型チェックの際に特定の部分型やプロパティを抽出して使用できるため、型システムの表現力と柔軟性が向上します。簡単に言うと、infer を使うことで、複雑な型の中から必要な部分だけを自動で抽出することができます。


私たちはLeapcell、Node.jsプロジェクトのホスティングの最適解です。

Leapcell

Leapcellは、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです:

複数言語サポート

  • Node.js、Python、Go、Rustで開発できます。

無制限のプロジェクトデプロイ

  • 使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。

比類のないコスト効率

  • 使用量に応じた支払い、アイドル時間は課金されません。
  • 例: $25で6.94Mリクエスト、平均応答時間60ms。

洗練された開発者体験

  • 直感的なUIで簡単に設定できます。
  • 完全自動化されたCI/CDパイプラインとGitOps統合。
  • 実行可能なインサイトのためのリアルタイムのメトリクスとログ。

簡単なスケーラビリティと高パフォーマンス

  • 高い同時実行性を容易に処理するためのオートスケーリング。
  • ゼロ運用オーバーヘッド — 構築に集中できます。

ドキュメントで詳細を確認!

Try Leapcell

Xでフォローする:@LeapcellHQ


ブログでこの記事を読む

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?