Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

TypeScript学習日記 その0011 とてもやさしいinfer入門

参考にさせていただいたページ

この記事について

inferまじで何もわからない。という私のような人が少しとっかかりをつかむ超入門記事です。

inferがわからない人の助けになれば幸いです。

でも何に使うと効果的なのかはこの記事を読んでもわかりません。

実例について

参考にさせていただいたページにはinferが使用されている実例として、ReturnTypeという組み込みのジェネリクスが挙げられています。

以下のようなコードだそうです。

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

これはTの部分に関数の型を渡すと、その関数の「返り値の型」を返すというものです。

「返り値の型」が取得できるのでReturnTypeなのでしょう。

ReturnTypeを使ってみる

まず自分で関数の型 MyFunction を定義してみます。

type MyFunction = () => 'hoge'

ReturnTypeを使ってみます。

type Hoge = ReturnType<MyFunction> // type Hoge = "hoge"

Hogeはstring literal型の "hoge" になりました。

ReturnTypeを読む

さきほどの「ReturnTypeを使ってみる」例を踏まえて、以下のコードを読んでみましょう。

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

(...args: any[]) の部分を読むと、引数は可変長引数でany型なので「引数はあっても無くてもよく、引数の型は何でも良い」ということが読み取れます。

また infer R の部分は返り値部分を推測する。つまり「返り値は何でも良い」ということが読み取れます。

つまり渡した型Tが関数の型であれば、Rが返ってきますので、さきほどの例ではstring literal typeの"hoge"が返ってきます。

もう少し考えてみる

inferの理解を深めるためにもう少し考えてみます。

以下のようにしたときtype Elem = "elm1" | "elm2"になります。

    type MyArr = ('elm1' | 'elm2')[]
    type ElemTypes<T> = T extends (infer E)[] ? E : any
    type Elem = ElemTypes<MyArr>

type MyArrは文字列'elm1'または'elm2'が入る配列の型です。

T extends (infer E)[]は渡されたTが配列の型だった場合にEを返します。

つまり、type Elem = "elm1" | "elm2"になります。

このような例を書いてしまいましたが、実際はこんなElemTypes<T>を定義しなくても、配列の要素の型が欲しい場合は以下のようにすれば同じ型が得られます。

type Elem = MyArr[number]