【问题标题】:Awaitable type in TypeScriptTypeScript 中的可等待类型
【发布时间】:2019-05-14 19:37:48
【问题描述】:

我在 JavaScript 中经常使用 async / await。现在我正在逐渐将我的部分代码库转换为 TypeScript。

在某些情况下,我的函数接受将被调用和等待的函数。这意味着它可能会返回一个承诺,只是一个同步值。我为此定义了Awaitable 类型。

type Awaitable<T> = T | Promise<T>;

async function increment(getNumber: () => Awaitable<number>): Promise<number> {
  const num = await getNumber();
  return num + 1;
}

可以这样调用:

// logs 43
increment(() => 42).then(result => {console.log(result)})

// logs 43
increment(() => Promise.resolve(42)).then(result => {console.log(result)})

这行得通。但是,必须为我所有使用 async/await 和 TypeScript 的项目指定 Awaitable 很烦人。

我真的不敢相信这种类型不是内置的,但我找不到。 TypeScript 有内置的可等待类型吗?

【问题讨论】:

  • 到底是什么问题?为什么需要在代码库的任何地方指定Awaitable?无论您的函数返回T 还是Promise&lt;T&gt;,您的函数都可以处理它
  • 另外,type Awaitable&lt;T&gt; = T | Promise&lt;T&gt; 并没有那么复杂,在多个项目中编写它会有那么大的问题
  • @Aron 但是,如果您有多个返回行,则必须将每个同步值包装在一个 Promise 中,这还不错,但您不必这样做。
  • @Aron 这是添加到帖子中的内容。如果使用Promise&lt;T&gt; 作为签名,() =&gt; 42 无效,但您可以在 typescript 中调用await 42
  • @T.J.Crowder 我创建了一个issue

标签: typescript async-await


【解决方案1】:

我相信这个问题的答案是:不,没有内置类型。

lib.es5.d.tslib.es2015.promise.d.ts 中,他们将T | PromiseLike&lt;T&gt; 用于您的Awaitable&lt;T&gt; 可能有意义的各个地方,例如:

/**
 * Represents the completion of an asynchronous operation
 */
interface Promise<T> {
    /**
     * Attaches callbacks for the resolution and/or rejection of the Promise.
     * @param onfulfilled The callback to execute when the Promise is resolved.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of which ever callback is executed.
     */
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

    /**
     * Attaches a callback for only the rejection of the Promise.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of the callback.
     */
    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}

lib.es5.d.ts 中定义 PromiseLikePromise 与您的 Awaitable 不同。

我想如果他们定义了一个,他们会在这些定义中使用它。

旁注:根据这些定义,在您的Awaitable 中使用PromiseLike 而不是Promise 可能更有意义:

type Awaitable<T> = T | PromiseLike<T>;

【讨论】:

    【解决方案2】:
    1. async/await 总是会导致语句被包装成一个 Promise,所以你的函数总是会返回一个 Promise。
    2. 一切都可以等待,无论是否异步,因此自定义 Awaitable 类型可能只是多余的......
    async function test() {
        const foo = await 5;
        console.log(foo);
    
        const bar = await 'Hello World';
        console.log(bar);
    
        const foobar = await Promise.resolve('really async');
        console.log(foobar);
    }
    
    test();
    

    Link to the ts playground

    恕我直言,您不需要额外输入,因为您的函数将始终具有:

    async function foo<T>(task: () => T | Promise<T>): Promise<T> {
      const result = await task();
    
      return result;
    }
    

    【讨论】:

    • 我不明白这是如何回答这个问题的。 OP 清楚地知道await 是如何工作的,并且您可以等待一个非thenable。问题是关于定义回调的类型,以便为回调参数提供的函数可以是函数返回T,也可以是返回Promise&lt;T&gt;的函数。
    • 它应该会有所帮助,因为: 1. Awaitable 是多余的,因为默认情况下一切都是等待的; 2. 一旦你使用async/await 关键字,那么你的函数将总是返回一个承诺,因此打字总是一致的(恕我直言)。
    • 不,Awaitable 不是多余的; example.
    • (继续我上面的评论,因为链接会占用评论限制。) OP 特别想迎合返回承诺和不返回承诺的回调,输入正确。
    • @T.J.Crowder 是正确的。我想指定将要等待的回调函数的返回类型。
    猜你喜欢
    • 2019-02-03
    • 2013-07-21
    • 1970-01-01
    • 2021-12-16
    • 2021-02-06
    • 2019-03-04
    • 1970-01-01
    • 2019-07-09
    • 2023-02-14
    相关资源
    最近更新 更多