💎

【TypeScript】ユーティリティ型のReturnTypeをConditional Typesで再定義してinferを理解する

2024/10/16に公開

こんにちは、ujitaです!

前回の記事に引き続き、ユーティリティ型をConditional Typesを使ってどのように定義するのか解説していきます。ユーティリティ型やConditional Typesについては前回の記事で説明したので、省略します。知らない方や忘れてしまった方はぜひ前回の記事を読んでいただけると幸いです。

https://zenn.dev/ujita/articles/2327748327996c

本記事では、TypeScriptに標準で用意されているユーティリティ型であるReturnTypeを、Conditional Typesを用いてどのように定義するかを解説します。また今回はinferというConditional Typesの中で使われる型演算子を活用するので、その説明も一緒にしたいと思います!

ReturnTypeとConditional Typesを使った定義

ReturnTypeとは?

ReturnType<Type> は、関数型 Type の戻り値の型を抽出するためのユーティリティ型です。以下に基本的な使用例を示します。

function getUser(id: number): { id: number; name: string } {
  return { id, name: 'John Doe' };
}

type UserReturnType = ReturnType<typeof getUser>;
// UserReturnType は { id: number; name: string } 型になります

このように、ReturnType を使用することで、関数の戻り値の型を簡単に取得できます。

Conditional Typesを使った定義

ReturnType<Type>はConditional Types と infer を用いて次のように定義されています。

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

T extends (...args: any[]) => any はTが任意の数の引数(型は any[])を取り、任意の型を返す関数型を表しています。分解すると、以下のような感じになります。

  • T: ジェネリック型パラメータ。
  • extends 型の制約を定義するキーワード。ここでは T が右辺の型に「割り当て可能かどうか」をチェックします。
  • (...args: any[]) => any 任意の数の引数(型は any[])を取り、任意の型を返す関数型。

inferの役割

infer は、Conditional Types の中で型を一時的に推論(抽出)するために使用されます。infer を用いることで、複雑な型から特定の部分を抽出し、新しい型として利用することが可能です。

T extends (...args: any[]) => infer Rの部分で T が関数型であるかをチェックします。

  • 関数型であれば、infer R により戻り値の型 R を推論します。

? R : never; の部分で戻り値の型を決定しています。

  • 条件が真 (true) であれば、推論された型 R を返します。
  • 条件が偽 (false) であれば、never 型を返します。

まとめ

inferは、TypeScriptのConditional Typesと組み合わせることで、型の一部を柔軟に抽出・推論する強力なツールです。ReturnTypeなどのユーティリティ型は、inferを活用して実装されており、これらを再定義することでinferの動作を深く理解することができます。
inferをさらに理解するために、他のユーティリティ型を再定義した記事を次回書いていこうと思うので、いいねとフォローをよろしくお願いいたします!

Discussion