にょっす速報🐮✋

TypeScript の型条件分岐: `T extends (...args: infer R) => unknown ? R : never`とは?

TypeScript の型条件分岐: `T extends (...args: infer R) => unknown ? R : never`とは?のサムネイル

この記事の目次

この記事を読んでいるあなたは、TypeScriptの型システムやジェネリクスに興味がある方ですね。ありがとうございます。今回は、TypeScriptで利用することができる条件付き型 (Conditional Type) と推論 (infer) について詳しく解説します。

extends とは?

extends は、型の条件分岐に使われるキーワードです。TypeScriptの公式ドキュメントには「Conditional Type Constraints」として紹介されています。これは、型に応じて条件を分岐させたい場合に使用します。
https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#conditional-type-constraints

例: 条件分岐による型の制約

例えば、次のようにextendsを使うことで、型Tstring型であればstring型を返し、それ以外であれば元のT型を返すことができます。

type ConditionalString<T> = T extends string ? string : T;

type IdString = ConditionalString<"123456">; // string
type IdNumber = ConditionalString<123456>;   // 123456

この例では、ConditionalString<"123456">string型を返しますが、ConditionalString<123456>はそのままの123456型を返します。

T extends (...args: infer R) => unknown ? R : never の意味

T extends (...args: infer R) => unknown ? R : never という条件は、「型Tが関数型であれば、その引数の型を取得する」という意味になります。

具体的には、この構文では次の2つのことを行っています。

  1. T が関数型かどうかを確認します。
  2. T が関数型である場合、その引数の型リストRを推論し、それを結果として返します。関数型でない場合は never を返します。

infer とは?

infer は「条件付き型の中で型を推論したい場合」に使用するキーワードです。TypeScriptドキュメントには「Inferring Within Conditional Types」として紹介されています。

例: 戻り値の型を取得する型

次の例では、関数の戻り値の型を取得するための条件付き型GetReturnType<T>を定義しています。

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

const func1 = () => "HelloWorld";
const func2 = (a: number, b: number) => a * b;

type TypeFunc1 = GetReturnType<typeof func1>; // string
type TypeFunc2 = GetReturnType<typeof func2>; // number
type TypeFunc3 = GetReturnType<"123456">;     // never

この例では、func1func2の戻り値の型がそれぞれ推論され、GetReturnType<typeof func1>string型、GetReturnType<typeof func2>number型になります。

型の意味を失わないための推論

inferで推論する際に、正確な型を取得するためにはRを使って型の戻り値を推論することが重要です。次のようにinferを省略した場合、すべての戻り値がany型になってしまい、型システムの意味が薄れてしまいます。

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

type TypeFunc1 = GetReturnType<typeof func1>; // any
type TypeFunc2 = GetReturnType<typeof func2>; // any

実際に使用されるケース

ここで、TypeScriptの型を駆使して、関数の引数の型リストを取得する方法を紹介します。

演習: 引数の型リストを取得する MyParameters

Parametersのジェネリック型を利用せず、自分で関数の引数の型リストを返す型を実装します。

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

const foo = (arg1: string, arg2: number): void => {};

type FunctionParamsType = MyParameters<typeof foo>; // [arg1: string, arg2: number]

この例では、fooの引数型である[string, number]が取得できます。引数の型がわかると、関数のテストやエラーハンドリングをより効率的に行うことができます。

まとめ

extendsinferを使うことで、TypeScriptでの型推論と条件分岐がより柔軟に行えるようになります。このような型システムを駆使して、より安全で効率的なコードを書くことが可能になります。TypeScriptを使用する際は、ぜひこれらのテクニックを活用してみてください。

);

コメント(2件)

1. 名無し
2024/11/11 08:28:24
ID: a9cd
T extends (...args: infer R) => unknown ? R : neverの使い方を知ることで、より高度な型定義ができるようになるのが魅力的ですね。

2. 名無し
2024/11/11 08:28:55
ID: fa6e
extendsやinferといった難しそうな型について、具体的なサンプルコードを交えながら丁寧に解説されているので、とても理解しやすかったです。特に関数の引数や戻り値の型を取得する方法が勉強になりました!


トピックス