如何在打字稿中使用fetch

Kok*_*oko 33 promise typescript

我在Typescript中使用window.fetch,但我无法将响应直接转换为我的自定义类型:

我通过将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;
      })
Run Code Online (Sandbox Code Playgroud)

Chr*_*ris 49

下面是一些示例,从基本到请求和/或错误处理后添加转换:

基础:

// 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 */
  })
Run Code Online (Sandbox Code Playgroud)

数据转换:

通常,您可能需要在将数据传递给使用者之前对数据进行一些调整,例如,展开顶级数据属性.这是直截了当的:

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 */
  })
Run Code Online (Sandbox Code Playgroud)

错误处理:

我认为你不应该直接在这个服务中直接捕获错误,而只是允许它冒泡,但如果你需要,你可以做以下事情:

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 */
  })
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,这是我迄今为止读过的对泛型的最好解释。为什么 Promise 可以是一种类型,但实际上是具有这种类型的数据,这仍然有点模糊...... (2认同)
  • 似乎没有将response.json方法定义为通用方法-在当前的`@ types / node-fetch`和当前的TypeScript`lib.dom.d.ts`中都没有,所以这个答案不是现在可行。因此,相反,我想我们必须将Promise &lt;T&gt;;作为return.json()返回? (2认同)

Rod*_*ati 13

实际上,在打字稿中的几乎任何地方,只要传递的类型兼容,将值传递给具有指定类型的函数就可以按需要工作。

话虽这么说,以下作品......

 fetch(`http://swapi.co/api/people/1/`)
      .then(res => res.json())
      .then((res: Actor) => {
          // res is now an Actor
      });
Run Code Online (Sandbox Code Playgroud)

我想将所有 http 调用包装在一个可重用的类中 - 这意味着我需要某种方式让客户端以所需的形式处理响应。为了支持这一点,我接受回调 lambda 作为包装方法的参数。lambda 声明接受任何类型,如下所示......

callBack: (response: any) => void
Run Code Online (Sandbox Code Playgroud)

但在使用中,调用者可以传递指定所需返回类型的 lambda。我从上面修改了我的代码,如下所示......

fetch(`http://swapi.co/api/people/1/`)
  .then(res => res.json())
  .then(res => {
      if (callback) {
        callback(res);    // Client receives the response as desired type.  
      }
  });
Run Code Online (Sandbox Code Playgroud)

这样客户端就可以通过回调来调用它,例如......

(response: IApigeeResponse) => {
    // Process response as an IApigeeResponse
}
Run Code Online (Sandbox Code Playgroud)


nic*_*nli 5

如果你看一下@types/node-fetch你会看到主体定义

export class Body {
    bodyUsed: boolean;
    body: NodeJS.ReadableStream;
    json(): Promise<any>;
    json<T>(): Promise<T>;
    text(): Promise<string>;
    buffer(): Promise<Buffer>;
}
Run Code Online (Sandbox Code Playgroud)

这意味着您可以使用泛型来实现您想要的目的。我没有测试这段代码,但它看起来像这样:

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

fetch(`http://swapi.co/api/people/1/`)
      .then(res => res.json<Actor>())
      .then(res => {
          let b:Actor = res;
      });
Run Code Online (Sandbox Code Playgroud)

  • 添加泛型类型会导致“预期有 0​​ 个类型参数,但得到了 1”,但这可能是因为我不使用“node-fetch”。本机获取的类型可能不同? (20认同)
  • 链接文件没有模板化的“json()”。如果它以前存在,那么现在就不存在了。 (19认同)
  • 很抱歉挖出一篇旧帖子,但是,`Body.json&lt;T&gt;` 签名已于 2018 年通过[此提交](https://github.com/DefinitelyTyped/DefinitelyTyped/commit/78cdbac#diff-)从DefinitelyTyped中删除。 16dd1699972b26236bcd5bc367af23fbL128)。浏览 [**node-fetch** &gt; `/src/body.js`](https://github.com/node-fetch/node-fetch/blob/master/src/body.js) 的历史记录,我不确定我是否见过以这种方式实现“json()”的时候。尼科,你有这个工作的例子吗,否则,我倾向于认为这没有。 (5认同)