TypeScript 中等待的类型是什么

Bab*_*med 12 types typescript

在最新版本的 TypeScript 4.5 中,有一个名为Awaited的新类型。看起来这种类型是用于处理承诺的。我发现文档中对此没有很好的描述,并且我在任何地方都没有找到任何更好的示例。

有人可以解释一下这种类型的用途及其工作原理吗?

先感谢您。

jca*_*alz 14

如果您正在寻找实用程序类型Awaited<T>更详细和解释性文档,您可能需要查看TypeScript 4.5 发行说明的相关部分以及实施拉取请求microsoft/TypeScript#45350

的目标是描述函数中Awaited<T>表示的(也许令人惊讶的)复杂类型操作。当你输入某种类型的值时,你将得到一个类型的值:awaitasyncawaitTAwaited<T>

async function foo<T>(x: T) {
    const y = await x;
    // const y: Awaited<T> in TS4.5 and above 
    // (just T in TS4.4 and below)
}
Run Code Online (Sandbox Code Playgroud)

T如果您正在使用的类型await不是Promise任何类型,则Awaited<T>与以下内容相同T

async function bar(x: string) {
    const y = await x;
    // const y: string
    // Awaited<string> is just string
}
Run Code Online (Sandbox Code Playgroud)

T如果您正在查找的类型await是 a ,Promise<U>其中U不是Promise任何类型,则Awaited<T>与 相同U

async function baz(x: Promise<string>) {
    const y = await x;
    // const y: string
    // Awaited<Promise<string>> is just string
}
Run Code Online (Sandbox Code Playgroud)

T当您输入的类型await是 a时,事情会变得更加复杂Promise<Promise<V>>;如果V不是 a Promise,则Awaited<T>与 相同V

async function qux(x: Promise<Promise<string>>) {
    const y = await x;
    // const y: string
}
Run Code Online (Sandbox Code Playgroud)

这是因为await 递归地解开任何Promises ,直到遇到非Promise(或一些可怕的错误条件,例如具有方法的非承诺对象then());你永远不应该Promise从以下内容中得到 a await

async function quux(x: Promise<Promise<Promise<Promise<string>>>>) {
    const y = await x;
    // const y: string
}
Run Code Online (Sandbox Code Playgroud)

因此,这Awaited<T>也意味着通过以下递归条件类型递归地解开 Promise :

/**
 * Recursively unwraps the "awaited type" of a type. 
   Non-promise "thenables" should resolve to `never`. 
   This emulates the behavior of `await`.
 */
type Awaited<T> =
    T extends null | undefined ? T : // special case for `null | undefined` 
                                     // when not in `--strictNullChecks` mode
        T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ? 
        // `await` only unwraps object types with a callable `then`. 
        // Non-object types are not unwrapped
            F extends ((value: infer V, ...args: infer _) => any) ? 
            // if the argument to `then` is callable, extracts the first argument
                Awaited<V> : // recursively unwrap the value
                never : // the argument to `then` was not callable
        T; // non-object or non-thenable
Run Code Online (Sandbox Code Playgroud)

它还处理联合类型;例如,如果你有一个东西是a或astring Promise<number>it await,那么你将得到astring anumber

async function union(x: string | Promise<number>) {
    const y = await x;
    // const y: string | number
}
Run Code Online (Sandbox Code Playgroud)

递归包装的联合依此类推:

async function wha(x: number | Promise<string | Promise<number | Promise<Promise<boolean>>>>) {
    const y = await x;
    // const y: string | number | boolean
}
Run Code Online (Sandbox Code Playgroud)

在 TypeScript 4.5 之前,上面的await方法大部分都可以工作,但是存在一些问题,特别是在Promise-combination 方法的行为方面,例如Promise.all()

async function oops(x1: Promise<string | Promise<number>>, x2: Promise<string | Promise<number>>) {
    const y = await Promise.all([x1, x2]);
    // const y: [string | Promise<number>, string | Promise<number>] in TS4.4 and below 
    // const y: [string | number, string | number] in TS4.5 and above 
}
Run Code Online (Sandbox Code Playgroud)

因此,引入该Awaited<T>类型是为了更全面地处理Promise操作的影响,面对人们报告为错误的一些奇怪的边缘情况(您可以在 microsoft/TypeScript#45350 中看到)。

在实践中,您可能不需要自己过多处理它,但它的存在很有帮助。

Playground 代码链接


Eve*_*ert 11

简短的版本是给定的Awaited<X>,您将得到:

X - If X was not a promise,
Y - If X was Promise<Y>
Z - If X had the type Promise<Promise<Z>>
Run Code Online (Sandbox Code Playgroud)

所以:

Awaited<number>  -> Gives you number
Awaited<Promise<string>> -> Gives you string 
Awaited<Promise<Promise<boolean>>> -> Gives you boolean
Run Code Online (Sandbox Code Playgroud)

这个想法是,在 Javascript 中,你可以等待非承诺并返回相同的值:

const x = await 5; // x = 5
Run Code Online (Sandbox Code Playgroud)

上面的例子在Awaited引入之前就已经有些可能了,但是当 Promise 类型像 一样嵌套时,就会变得很奇怪Promise<Promise<Y>>,所以 tl;dr 是:

类型Awaited<X>是当你await使用 type 的东西时你得到的X。换句话说,它会删除任意数量的Promise包装。(或者更具体地说,PromiseLike)。