TypeScriptでfetchを使用する方法 質問する

TypeScriptでfetchを使用する方法 質問する

使っていますウィンドウ.フェッチTypescript では、レスポンスをカスタム型に直接キャストできません。

私は Promise の結果を中間の 'any' 変数にキャストすることで、この問題を回避しています。

これを行う正しい方法は何でしょうか?

import { Actor } from './models/actor';

fetch(`http://swapi.co/api/people/1/`)
      .then(res => res.json())
      .then(res => {
          // this is not allowed
          // let a:Actor = <Actor>res;

          // I use an intermediate variable a to get around this...
          let a:any = res; 
          let b:Actor = <Actor>a;
      })

ベストアンサー1

編集

しばらく前にこの回答を書いてから、いくつか変更がありました。コメントで述べたように、response.json<T>はもう有効ではありません。どこで削除されたのかはわかりません。

以降のリリースでは、次の操作を実行できます。

// Standard variation
function api<T>(url: string): Promise<T> {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(response.statusText)
      }
      return response.json() as Promise<T>
    })
}


// For the "unwrapping" variation

function api<T>(url: string): Promise<T> {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(response.statusText)
      }
      return response.json() as Promise<{ data: T }>
    })
    .then(data => {
        return data.data
    })
}

古い回答

以下に、基本的な例から、リクエスト後やエラー処理後の変換の追加まで、いくつかの例を示します。

基本:

// Implementation code where T is the returned data shape
function api<T>(url: string): Promise<T> {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(response.statusText)
      }
      return response.json<T>()
    })

}

// Consumer
api<{ title: string; message: string }>('v1/posts/1')
  .then(({ title, message }) => {
    console.log(title, message)
  })
  .catch(error => {
    /* show error message */
  })

データ変換:

多くの場合、データを消費者に渡す前に、トップレベルのデータ属性をアンラップするなど、データを微調整する必要があります。これは簡単です:

function api<T>(url: string): Promise<T> {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(response.statusText)
      }
      return response.json<{ data: T }>()
    })
    .then(data => { /* <-- data inferred as { data: T }*/
      return data.data
    })
}

// Consumer - consumer remains the same
api<{ title: string; message: string }>('v1/posts/1')
  .then(({ title, message }) => {
    console.log(title, message)
  })
  .catch(error => {
    /* show error message */
  })

エラー処理:

このサービス内で直接エラーをキャッチするのではなく、単にバブルさせるだけにすべきだと私は主張しますが、必要な場合は次の操作を実行できます。

function api<T>(url: string): Promise<T> {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error(response.statusText)
      }
      return response.json<{ data: T }>()
    })
    .then(data => {
      return data.data
    })
    .catch((error: Error) => {
      externalErrorLogging.error(error) /* <-- made up logging service */
      throw error /* <-- rethrow the error so consumer can still catch it */
    })
}

// Consumer - consumer remains the same
api<{ title: string; message: string }>('v1/posts/1')
  .then(({ title, message }) => {
    console.log(title, message)
  })
  .catch(error => {
    /* show error message */
  })

おすすめ記事