TypeScriptのPromise<T>を使うときはAwaited<T>も使うべし

Promise<T>とは

Promise<T>は非同期操作の結果を表し、最終的には成功(resolved)または失敗(rejected)のいずれかの状態になることを示します。

APIのJSONのデータをfetchで取得するときはPromise<T>を使わない場合は以下のようなコードになります。

TypeScript
async function getProduct(id: number) {
  const response = await fetch(`https://dummyjson.com/products/${id}`)

  if (!response.ok) {
    throw new Error(`Error status: ${response.status}`)
  }

  const data = await response.json()
  return data
}

(async () => {
  const product = await getProduct(1)
  console.log(product.title)
  // Essence Mascara Lash Princess
})()

もし、「product.title」が「product.titel」になっていてもproductの型が「any」になっているため、このコードだと警告が出ません。

Promise<T>で返り値の型を追加すると、「product.titel」と間違えたときに警告がエディタ上で表示されるようになります。

TypeScript
type Product = {
  id: number
  title: string
  // 以下略
}

async function getProduct(id: number): Promise<Product> {
  const response = await fetch(`https://dummyjson.com/products/${id}`)

  if (!response.ok) {
    throw new Error(`Error status: ${response.status}`)
  }

  const data = await response.json()
  return data
}

(async () => {
  const product = await getProduct(1)
  console.log(product.titel)
  // Property 'titel' does not exist on type 'Product'. Did you mean 'title'?
})()

Awaited<T>でawait漏れのときに警告を表示

getProduct(1)でawaitが書かれていない場合、Promise<Product>の型が付いているので、console.log(product.title)の場合は警告が表示されます。

TypeScript
(async () => {
  const product = getProduct(1)
  console.log(product.title)
  // Property 'title' does not exist on type 'Promise<Product>'
})()

しかし、console.log(product)だと[object Promise]を代入したと判断されるので、警告が表示されません。

TypeScript
(async () => {
  const product = getProduct(1)
  console.log(product)
  // [object Promise]
})()

Awaited<ReturnType<typeof getProduct>>で型を作成して、productに付ければ、Type 'Promise' is missing 〜 の警告が表示されるようになります。

TypeScript
type ProductType = Awaited<ReturnType<typeof getProduct>>

(async () => {
  const product: ProductType = getProduct(1)
  // Type 'Promise<Product>' is missing the following properties from type 'Product': id, titles
  console.log(product)
})()

以上のように、コードの記述ミスをいままで以上に防ぐことができるようになるので、Promise<T>を使うときはAwaited<T>も使うことをオススメします。

TypeScriptのPromise<T>とAwaited<T>を使用したサンプル