【问题标题】:Async function that returns a Promise or String - Typescript返回 Promise 或字符串的异步函数 - Typescript
【发布时间】:2020-02-15 03:04:42
【问题描述】:

是否可以从函数中返回不仅仅是一个 Promise?

const someFunc = async <T>(url: string): Promise<T> => {
  const res = await fetch(url);

  if (!res.ok) return { error: 'error text' };
  return await res.json();
}

根据条件,上面的函数可以返回一个带有{ error: 'string' }的promise或一个对象。我在这里遇到错误:TS2322: Type '{ error: any; }' is not assignable to type 'T'.   '{ error: any; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.

我试过用:

const someFunc = async <T>(url: string): Promise<T> | Promise<string> => {}

这会引发错误:TS1055: Type 'Promise&lt;T&gt; | Promise&lt;string&gt;' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.

我也试过这个变种:

const someFunc = async <T>(url: string): Promise<T | { error: string }> => {}

但是当我使用这个功能时:

interface IResponse {
  access_token: string;
  refresh_token: string;
  userRoles: string[];
  error: any;
}

const result = await someFunc<IResponse>(url);
console.log(result.access_token); // throws an error
// TS2339: Property 'access_token' does not exist on type '{ error: string; } | IResponse'.   Property 'access_token' does not exist on type '{ error: string; }'.

使用类型保护更新

If ('access_token' in result) {
  console.log(result.access_token);
}

这很好用,使用来自IResponse 接口的access_token

【问题讨论】:

  • "async 函数声明定义了一个异步函数 — 一个返回 AsyncFunction 对象的函数。异步函数的运行顺序与通过事件循环的其余代码不同,返回一个隐式Promise作为结果。" (Source)
  • 你为什么在这里使用泛型?
  • @voiys 因为我会重用这个函数并且取决于端点它会有不同的响应形状?不是很明显吗?
  • @voiys 不管好坏,它是一种常见的模式,函数从网络返回对象以将结果的预期类型指定为类型参数。它并不比类型断言更好,但稍微方便一些。
  • 我刚开始学习 ts 所以我想知道:p

标签: typescript


【解决方案1】:

异步的返回类型应该是Promise,但Promise的结果类型可以是联合:

const someFunc = async <T>(url: string): Promise<T | { error: string}> => {
  const res = await fetch(url);

  if (!res.ok) return { error: 'error text' };
  return await res.json();
}

Playground Link

要使用函数结果,您需要缩小结果的类型以查看它是错误还是实际结果:


interface IResponse {
  access_token: string;
  refresh_token: string;
  userRoles: string[];
}

async function test() {
  const result = await someFunc<IResponse>("url");
  if (!('error' in result)) {
    console.log(result.access_token);
  }
}

Playground Link

请参阅手册中关于type guards 的部分

【讨论】:

  • 我更新了我的问题,请看一下。
  • @AlexanderKim 这很正常,然后您需要缩小结果的类型。如果您不确定这不是错误,如何将result 用作IResponse?我将很快用一个用法示例更新答案
  • 谢谢,我第一次听说类型保护。 WebStorm 向我建议,但我不明白它实际上是什么。
  • 你能解释一下,在我的IRespoinse界面中,我有error: any,如果我console.log(result.error)它使用这个接口,但为什么它不使用这个接口和result.access_token?我还在原始问题中更新了我的工作变体。
  • @AlexanderKim error 将是 IResponse{ error: string} 之间的公共属性,因此它可以访问,这是工会的规则。我在我的代码示例中将其删除,以便我可以使用它来区分 IResponse{ error: string}。您可以保留error 并区分不在这两种类型中的属性。 (例如if ('access_token' in result) { console.log(result.access_token); }
猜你喜欢
  • 2015-02-18
  • 2023-03-13
  • 2020-07-09
  • 2017-10-16
  • 1970-01-01
  • 2018-04-13
  • 2019-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多