【问题标题】:Using fetch in Typescript with data transformations在 Typescript 中使用 fetch 进行数据转换
【发布时间】:2021-12-07 02:21:15
【问题描述】:

我正在尝试将 js 代码转换为 ts,我有这个:

function api<T>(url: string): Promise<T> {
  return fetch(url)
    .then((res) => {
      return res.json().then((resJson: T) => ({
        ok: res.ok,
        status: res.status,
        body: resJson,
      }));
    })
    .then((res) => {
     if (res.ok) {
       return res.body;
     }
     return Promise.reject({
       status: res.status,
       message: res.body.message,
     });
    });
}

我不知道如何解决这个问题

message: res.body.message // Property 'message' does not exist on type 'T'

只有当 res.ok === false 时,我的 body-response 才包含“message”属性作为可选属性。如何解决这种情况? 大概用法:

type ResBody = {
  success: boolean;
  message?: string;
  data?: string[];
};

api<ResBody>("https://example.com")
  .then(({ success, data }) => {
    console.log(success, data);
  })
  .catch((err) => {
    console.log(err.message, err.status)
  });

【问题讨论】:

  • 你能在这里解释一下你对泛型的使用吗?特别是泛型类型Tapi&lt;T&gt; 怎么称呼?也就是说T的类型实际上是如何确定的。最后的res.bodyT 类型,因为你在前面的body: resJson 中这样做了,并且在上面声明resJsonT 类型...但是T 没有消息属性,因为它是未知类型!给我详细信息,我可以很容易地解决这个问题。或提供minimal reproducible example
  • 添加了对帖子的更改
  • 再一次,你能解释一下为什么api&lt;T&gt;首先使用泛型吗?也就是说,你为什么不只是说resJson: ResBody?必须有使用泛型的理由。答案对于提供正确的解决方案很重要。否则我下面的答案是一个最好的猜测/破解。
  • 刚开始学ts,拿了here的泛型例子
  • 好吧,我的错。 Promise 被定义为泛型,因此您(用户)可以使用任何解析类型加载它,然后能够在结果中引用它。在这种情况下,我的回答会奏效......但我会在几分钟内更新它并提供更多细节。

标签: typescript fetch


【解决方案1】:

Promise 类型有一个泛型参数T,以便您可以声明异步函数的返回类型。这允许您以类型安全的方式引用该返回值。

您的第一个then 返回一个对象,其中body 分配了T 类型的值,然后您的下一个then 将其作为res 输入。这意味着res 被推断为具有T 类型的body。然后您引用res.body.message,但您没有在哪里声明类型T 是具有字段message 的类型。

当您在function api&lt;T&gt; 声明中声明泛型参数T 时,您需要这样做:

function api<T extends ResBody>(url: string): Promise<T> {
  return fetch(url)
    .then((res) => {
      return res.json().then((resJson: T) => ({
        ok: res.ok,
        status: res.status,
        body: resJson,
      }));
    })
    .then((res) => {
      if (res.ok) {
        return res.body;
      }
      return Promise.reject({
        status: res.status,
        message: res.body.message,
      });
    });
}

T extends ResBody 告诉 Typescript 泛型类型 T,无论它最终是什么,都将是 ResBody 或其子类型,因此将有一个可选的 message 类型为 string 的字段。

您可以比这更通用,即如果T 可以是包含message 字段的任何 类型,如下所示:

function api<T extends {message?: string}>(url: string): Promise<T> {
  return fetch(url)
    .then((res) => {
      return res.json().then((resJson: T) => ({
        ok: res.ok,
        status: res.status,
        body: resJson,
      }));
    })
    .then((res) => {
     if (res.ok) {
       return res.body;
     }
     return Promise.reject({
       status: res.status,
       message: res.body.message,
     });
    });
}

T extends {message?: string} 告诉 Typescript 泛型类型 T,无论它最终是什么,都有一个可选的 message 类型为 string 的字段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-08-02
    • 2019-08-22
    • 2020-06-07
    • 2021-02-25
    • 2019-06-29
    • 2022-01-22
    • 2019-05-12
    • 1970-01-01
    相关资源
    最近更新 更多