如何解开 Promise 的类型? [英] How to unwrap the type of a Promise?

查看:64
本文介绍了如何解开 Promise 的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下代码:

async promiseOne() {
  return 1
} // => Promise<number>

const promisedOne = promiseOne()

typeof promisedOne // => Promised<number>

我将如何提取承诺结果的类型(在这个简化的例子中是一个数字)作为它自己的类型?

How would I go about extracting the type of the promise result (in this simplified case a number) as its own type?

推荐答案

TypeScript 4.5

Awaited 类型现在内置于语言中,因此您无需自己编写.

TypeScript 4.5

The Awaited type is now built in to the language, so you don't need to write one yourself.

type T = Awaited<Promise<PromiseLike<number>> // => number

TypeScript 4.1 到 4.4

您可以使用多种可能的定义自行实现.最简单的是:

TypeScript 4.1 through 4.4

You can implement this yourself, with several possible definitions. The simplest is:

type Awaited<T> = T extends PromiseLike<infer U> ? U : T
// Awaited<Promise<number>> = number

请注意,此类型使用 PromiseLike 而不是 Promise.这对于正确处理用户定义的可等待对象很重要.

Note that this type uses PromiseLike rather than Promise. This is important to properly handle user-defined awaitable objects.

这使用条件类型来检查T 看起来像一个承诺,如果是的话就解开它.然而,这将不正确地处理Promise>,将其解包为Promise.等待一个承诺永远不会给出第二个承诺,所以更好的定义是递归解包承诺.

This uses a conditional type to check if T looks like a promise, and unwrap it if it does. However, this will improperly handle Promise<Promise<string>>, unwrapping it to Promise<string>. Awaiting a promise can never give a second promise, so a better definition is to recursively unwrap promises.

type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T
// Awaited<Promise<Promise<number>>> = number

TypeScript 4.5 使用的定义(source) 比这更复杂,以涵盖不适用于大多数用例的边缘情况,但它可以放入任何 TypeScript 4.1+ 项目.

The definition used by TypeScript 4.5 (source) is more complicated than this to cover edge cases that do not apply to most use cases, but it can be dropped in to any TypeScript 4.1+ project.

在 TypeScript 4.1 之前,该语言没有有意支持递归类型别名.上面显示的简单版本仍然有效,但是递归解决方案需要一个额外的对象类型来欺骗编译器认为该类型不是递归的,然后使用 索引访问类型.

Before TypeScript 4.1, the language did not have intentional support for recursive type aliases. The simple version shown above will still work, but a recursive solution requires an additional object type to trick the compiler into thinking that that the type is not recursive, and then pulling the property out that we want with an indexed access type.

type Awaited<T> = T extends PromiseLike<infer U>
  ? { 0: Awaited<U>; 1: U }[U extends PromiseLike<any> ? 0 : 1]
  : T

官方不支持,但实际上完全没问题.

This is officially not supported, but in practice, completely fine.

在 TypeScript 2.8 之前,这是不可能直接实现的.解开一个没有 2.8 中引入的条件类型的类似 promise 的类型需要泛型类型在对象上可用,以便可以使用索引访问类型来获取值.

Before TypeScript 2.8 this is not directly possible. Unwrapping a promise-like type without the conditional types introduced in 2.8 would require that the generic type be available on the object, so that indexed access types can be used to get the value.

如果我们将类型的范围限制为单一级别的承诺,并且只接受承诺,那么在 2.8 中使用 声明合并 将属性添加到全局 Promise 接口.

If we limit the scope of the type to a single level of promises, and only accept promises, it is technically possible to do this in 2.8 by using declaration merging to add a property to the global Promise<T> interface.

interface Promise<T> {
    __promiseValue: T
}
type Awaited<T extends Promise<any>> = T["__promiseValue"]

type T = Awaited<Promise<string>> // => string

这篇关于如何解开 Promise 的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆