TypeScriptでPromiseの型パラメータを取り出す

#やりたいこと

A = Promise<B>である際にAからBを導き出したい。

type A = Promise<B>

type C = /* AからBを取り出したい */

#やりかた

inferを使う。

type PromiseType<T extends Promise<any>> = T extends Promise<infer P>
  ? P
  : never

type A = Promise<B>

type C = PromiseType<A> // B

型名の直後のextends Promise...はなくても動くが、使う際にわかりやすくなるため個人的には書くことを推奨。

ちなみにutility-typesというパッケージがこの型を公開しているので、ユーティリティ型を多用する場合はそちらを使ったほうがよい。

また、Bluebird のような似非 Promise を(or も)使いたい場合はPromiseLikeを使うとよい。

type PromiseType<T extends PromiseLike<any>> = T extends PromiseLike<infer P>
  ? P
  : never

type A = PromiseType<Promise<number>> // number

import * as Bluebird from 'bluebird'

type B = PromiseType<Bluebird<string>> // string

このinferを使った型パラメータの抽出は書き方を覚えておくと、さくっと書けて結構便利。

interface Box<T> {
  value: T
}

type BoxType<T extends Box<any>> = T extends Box<infer P> ? P : never

type A = Box<number>

type B = BoxType<A> // number

#どんなときに必要か

基本的には外部のライブラリを使う際、特にPromiseを返す関数の結果の型を使いたい場合に役立つ。

// a.ts
export const someApi = () => Promise.resolve(0)

// b.ts
import { someApi } from 'a.ts'

type ResponseOfApi = PromiseType<ReturnType<typeof someApi>>

function mutateApiResponse(res: ResponseOfApi) {
  /* ... */
}

mutateApiResponse(await someApi())