【问题标题】:Is there a difference in the Promise type returned by an ordinary function and an async function?普通函数和异步函数返回的 Promise 类型有区别吗?
【发布时间】:2018-03-08 06:35:56
【问题描述】:

假设我有一个带有以下(最新)包的 Typescript 项目:

  • q@1.5.0
  • typescript@2.5.2
  • @types/q@1.0.5

现在假设在我的项目中,我定义了一个返回 Promise 的函数(由 Typescript 的原生环境声明定义):

import * as q from "q";

function doSomethingElseAsync(): Promise<number> {
    return q.Promise<number>((resolve, reject) => {
        setTimeout(() => resolve(1), 5000);
    });
}

编译时,Typescript 报错如下:

error TS2322: Type 'Q.Promise<number>' is not assignable to type 'Promise<number>'.
  Types of property 'then' are incompatible.
    Type '<U>(onFulfill?: ((value: number) => IWhenable<U>) | undefined, onReject?: ((error: any) => IWhena...' is not assignable to type '<TResult1 = number, TResult2 = never>(onfulfilled?: ((value: number) => TResult1 | PromiseLike<TR...'.
      Types of parameters 'onFulfill' and 'onfulfilled' are incompatible.
        Type '((value: number) => TResult1 | PromiseLike<TResult1>) | null | undefined' is not assignable to type '((value: number) => IWhenable<TResult1 | TResult2>) | undefined'.
          Type 'null' is not assignable to type '((value: number) => IWhenable<TResult1 | TResult2>) | undefined'.

有一段时间,我认为这是因为 Q Promises 与 Typescript 的原生声明不兼容。但是,如果我在函数定义中添加async 关键字,错误就会完全消失。

我对这种行为感到很困惑。这是 Typescript、Q 或 Q 类型中的错误吗?或者这是编译器的一些深奥但预期的行为?

【问题讨论】:

  • 可能相关? stackoverflow.com/questions/42689713/… 基本上...... q 承诺不是原生承诺。就像蓝鸟承诺不是原生承诺一样。
  • 只要它符合 Typescript 所期望的接口,它是否是原生承诺并不重要。 Q 和 Bluebird 的 promise 在实践中运行良好。
  • 对,但更重要的是,它们与界面匹配吗?我不认为他们这样做。
  • 啊,我认为你是对的。我将 async 函数的返回类型交换为 q.Promise 并得到一个编译器错误,说“它没有引用与 Promise 兼容的构造函数值”。这是有道理的,因为q.Promise 不是您使用new 调用的构造函数。

标签: typescript promise async-await q


【解决方案1】:

我的猜测是,将 async 关键字添加到您的函数会导致 Javascript 将该函数的返回值包装在本机 Promise 中,以便该函数返回一个承诺还是一个值,结果将是承诺可以awaited。

例如,它会做这样的事情:

Promise.resolve().then(() => doSomethingElseAsync())

如果没有 async 关键字,您将返回 q 承诺,它不是本机 Promise 的实例,因此您会收到类型错误。

我相信它也会像这样正常工作(删除q):

function doSomethingElseAsync(): Promise<number> {
    return Promise<number>((resolve, reject) => {
        setTimeout(() => resolve(1), 5000);
    });
}

或者,如果您的环境不包含本机 Promise 类,则更改返回类型可能会起作用,如下所示:

function doSomethingElseAsync(): q.Promise<number> {
    return q.Promise<number>((resolve, reject) => {
        setTimeout(() => resolve(1), 5000);
    });
}

【讨论】:

  • 将返回值包装在原生 Promise 中听起来更像是 async/await 的实现细节。一旦 JavaScript 被输出,类型就不再考虑了。如果我的目标是没有实现原生承诺的 ES5,那么删除 Q 将不起作用。这就是为什么我使用像 Q 这样的外部实现。
  • 如果您没有原生可用的 Promises,我也用潜在的 ES5 解决方案更新了答案
  • 另外,是的,抱歉,包装更多的是关于 async/await 如何工作与如何解决您的问题的潜在想法。
【解决方案2】:

看起来问题只是 Q 承诺与 async/await 不兼容。

我尝试将异步函数的返回类型从原生 Promise 交换为 q.Promise。编译器现在给我这个错误:

Type '<T>(resolver: (resolve: (val?: T | PromiseLike<T> | undefined) => void, reject: (reason?: any) =>...' is not a valid async function return type in ES5/ES3 because it does not refer to a Promise-compatible constructor value.
  Type '<T>(resolver: (resolve: (val?: T | PromiseLike<T> | undefined) => void, reject: (reason?: any) =>...' provides no match for the signature 'new <T>(executor: (resolve: (value?: T | PromiseLike<T> | undefined) => void, reject: (reason?: any) => void) => void): PromiseLike<T>'.

它说返回类型“在 ES5/ES3 中不是有效的异步函数返回类型,因为它没有引用与 Promise 兼容的构造函数值。”这是有道理的,因为q.Promise 不是您可以使用new 调用的构造函数。相比之下,Bluebird 等其他 Promise 实现确实具有兼容的构造函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-09
    • 2017-10-16
    • 1970-01-01
    • 2018-04-13
    • 2019-10-23
    相关资源
    最近更新 更多