【问题标题】:How to make typescript think resolved Promise<T> as Type T如何使打字稿认为已将 Promise<T> 解析为 Type T
【发布时间】:2020-09-14 22:25:35
【问题描述】:

我是 typescript 的新手,我正在创建一些东西,但遇到了使用 javascript 时从未发生过的问题。

假设我们有 async 函数返回 Promise&lt;ResultSet&gt;

interface ResultSet {
  status: number; // 0 for success 1 for failure
  data?: any;
}

const getDataFromServer = async (parameter: string): Promise<ResultSet> => {
   const response = await fetch(<--Prameters-->);
   return await response.json();
}

它总是将它的值返回为Promise

并且它需要连接到接口,以便某些模块可以使用它。它将使用上面的请求更改全局变量的值。并且需要返回动作结果(成功或失败代码)。这是在某处很多地方使用的行动的结果。

const storeData = async (parameter: string): number => {
  const result = await getDataFromServer(parameter);
  if (result.status == 0) {
    SOME_GLOBAL_VARIABLE.setState({ data: result.data });
  }
  return result.status;
}

如您所料,上面的函数定义在async (parameter: string): number 附近弹出一个错误,因为函数必须返回 Promise,因为它是async 函数。 所以它需要在下面,

const storeData = async (parameter: string): Promise<number> => {
  const result = await getDataFromServer(parameter);
  if (result.status == 0) {
    SOME_GLOBAL_VARIABLE.setState({ data: result.data });
  }
  return result.status;
}

问题由此开始。因为函数的返回类型是Promise,与此相关的所有其他函数的接口必须将该结果状态定义为Promise&lt;number&gt;,而不是number。它将全局影响整个服务器代码。 另外,SOME_GLOBAL_VARIABLEdata 也需要输入为Promise&lt;T&gt;

据我所知,没有办法将 promise 对象转换为普通对象。

我想切断这种无休止的承诺链。有什么办法吗?还是只是我的误解?即使将async ~ await 替换为then() ~ catch() 也失败了,因为它似乎也返回了Promise

Promise 保证它的值是否成功解析。但是,在某些时候,它已经被保证为 Resolve。但是没有办法处理这种情况。

我该如何处理这种情况?使用打字稿时,这似乎很常见。但我不知道该怎么做。

【问题讨论】:

  • 这似乎是对处理异步功能的误解。您如何处理 fetch 的使用和后续回调不会从 JavaScript 更改为 TypeScript。在 JavaScript 和 TypeScript 中,您仍然需要 await Promise 或使用 then 回调。您不需要将SOME_GLOBAL_VARIABLE 的类型更改为Promise&lt;T&gt;,因为那是在异步部分之后,因此数据已经解析。

标签: typescript asynchronous promise


【解决方案1】:

这和普通的 JavaScript 没有什么不同,只是 TypeScript 给它起了个名字。

简短的回答是否定的,您不能将对象的承诺转换为对象本身。这不是因为 TypeScript,而是因为 Promise API(或异步代码的本质)。

一旦处理了promises / async / await,你唯一可以访问promise 类型的地方就是then 处理程序中(或者在使用await 之后):

// Using promises
storeData().then((result: number) => { /* result is a number here, not a promise of a number */ });

// Using async / await
const result = await storeData(); // again, result is a number, not a promise of a number

因此,为了避免基于您的所有代码承诺,您需要从 then 处理程序(或在 await 之后)调用它:

// An example of a promise-less function somewhere in your code
const someOtherFunction = (result: number) => { /* do something with your result */ };

storeData().then(result => {
  // this works since result is a number here
  someOtherFunction(result);
});

您当然可以编写一个包装承诺的抽象,假设是一个具有value 属性的对象,它等待承诺并在解决后将value 设置为自身。但是,您仍然需要等待 promise 解决才能获得分辨率值。

【讨论】:

  • 你的意思是它会被视为number 而不是Promise&lt;number&gt;then() 函数内?也很抱歉造成混淆,我不打算将 convert 转换为普通类型,但将 treated 作为普通类型,这样我就不必更改与请求相关的所有接口。如果是这样,这就是我的意图。非常感谢您的回答!
【解决方案2】:

今晚我吃了汉堡。我们没有包子,所以我妻子去买了一些。直到我妻子带着面包从店里回来,我才能组装汉堡。因此,我也不得不等待吃包子,洗盘子等等。

我希望这个例子不会太离奇;异步依赖链在“现实生活”中似乎相当直接,虽然这根本不是直接的类比,但我希望它能够在某种程度上说明为什么 typescript 给出了它的类型。

正如@ján-jakub-naništa 的回答所指出的,javascript 中的情况与打字稿中的情况完全相同;只是打字稿让正在发生的事情变得更加明显。

有很多方法可以摆脱这种异步函数的链接,但最终您仍需要等待该值。我能建议的最好的方法是尽可能地隔离你的异步代码;例如,如果您有一个Promise&lt;number&gt;,则该承诺的解决方案调用一个只接受number 的函数。这样您就可以避免代码被不必要的Promise 类型“污染”。

【讨论】:

    猜你喜欢
    • 2021-01-15
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 2022-01-15
    • 1970-01-01
    • 2017-01-28
    相关资源
    最近更新 更多