1分でわかるTypeScriptのinferの使い方

TypeScriptのinferとは

TypeScriptのinferは条件型(Conditional Types)で使用される特別なキーワードです。

主にジェネリック型を使った型推論の際に役立ちます。

inferを使わないと作れない型もあるので、TypeScriptを使うなら必ず覚えておく必要があります。

inferの使い方

もしジェネリック型を使用してExtractType<T>で指定した型を作成したい場合は以下のようになります。

TypeScript
type ExtractType<T> = T

type Ex1 = ExtractType<number> // number
type Ex2 = ExtractType<string> // string
type Ex3 = ExtractType<boolean> // boolean

Tが配列だとtypeの方もそれぞれ配列になります。

TypeScript
type ExtractType<T> = T

type Ex1 = ExtractType<number[]> // number[]
type Ex2 = ExtractType<string[]> // string[]
type Ex3 = ExtractType<boolean[]> // boolean[]

しかし、例えばnumber[] を受け取った場合は配列ではなく、numberで渡したいことがあります。

そんなときは「T extends Array<infer U>」にして、条件型で「? U : never」を返すことで想定通りの型を作れます。

TypeScript
type ExtractType<T> = T extends Array<infer U> ? U : never

type Ex1 = ExtractType<number[]> // number
type Ex2 = ExtractType<string[]> // string
type Ex3 = ExtractType<boolean> // never

「? U : never」なので配列でない場合はneverを返していますが、「? U : T」にすると配列でない場合は指定した型をそのまま返します。

TypeScript
type ExtractType<T> = T extends Array<infer U> ? U : T

type Ex1 = ExtractType<number[]> // number
type Ex2 = ExtractType<string[]> // string
type Ex3 = ExtractType<boolean> // boolean

配列の最初や最後のプロパティの型を返す

inferを使用すれば配列の最初や最後のプロパティの型を返すことも簡単にできます。

TypeScript
type First<T extends any[]> = T extends [infer U, ...any[]] ? U : never
type F1 = ['a', 'b', 'c']
type F2 = [3, 2, 1]
type First1 = First<F1> // expected 'a'
type First2 = First<F2> // expected 3

type Last<T extends any[]> = T extends [...infer rest, infer U] ? U : never
type L1 = ['a', 'b', 'c']
type L2 = [3, 2, 1]
type last1 = Last<L1> // expected 'c'
type last2 = Last<L2> // expected 1

inferでオブジェクトのFlatten型を作成する

inferはオブジェクトのFlatten型を作成するによく使われます。

TypeScript
type Flatten<T> = T extends Array<infer U> ? U : T

const obj = [
  {
    id: 1,
    name: 'foo',
  },
  {
    id: 2,
    name: 'bar',
  }
]
type MyObj = Flatten<typeof obj>
/*
type MyObj = {
  id: number
  name: string
}
*/

以上のコードを覚えれば、inferを使いこなせるようになるでしょう。