如何打开承诺的类型

时间:2017-12-28 16:57:01

标签: typescript

说我有以下代码:

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

const promisedOne = promiseOne()

typeof promisedOne // => Promised<number>

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

8 个答案:

答案 0 :(得分:18)

Typescript 2.8开始,现在可以通过利用条件类型来实现,这是一个基本的例子:

UnsatisfiableError: The following specifications were found to be in conflict:
  - dlib
  - xlwt
Use "conda info <package>" to see the dependencies for each package.

扩展function promiseOne() { return Promise.resolve(1) } const promisedOne = promiseOne() type ThenArg<T> = T extends Promise<infer U> ? U : T type PromiseOneThenArg = ThenArg<typeof promisedOne> // => number 帮助程序以处理函数返回类型也可能很有用。

ThenArg

答案 1 :(得分:7)

首先,TypeScript 4.1 release notes具有以下代码段:

type Awaited<T> = T extends PromiseLike<infer U> ? Awaited<U> : T;

它可以让您解决诸如const x = (url: string) => fetch(url).then(x => x.json())之类的问题,但是将Jon Jaques的回答与ErikE的评论相结合,并且考虑到您使用的版本低于4.1,我们得到:

type Await<T> = T extends PromiseLike<infer U> ? U : T

和示例:

const testPromise = async () => 42
type t1 = Await<ReturnType<typeof testPromise>>
// t1 => number

答案 2 :(得分:6)

如果您有权访问npm模块,则可以使用type-fest

import {PromiseValue} from 'type-fest';

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

PromiseValue<promiseOne()>
//=> number

答案 3 :(得分:3)

计划实施此功能的Typescript 3.9。不幸的是,它已经被移回了,它可能是4.0版本。

新类型将称为awaited。由于向后兼容性问题,它被延迟了。

A related discussion on GitHub.

答案 4 :(得分:2)

一个老问题,但是我想加2美分。使用Promise类型来解约是很方便的,但是我发现我通常很想像await运算符一样来弄清楚“ thenable”对象的值。

为此,我写了一个Await<T>助手,它可以解开promise和随后的对象:

type Await<T> = T extends {
    then(onfulfilled?: (value: infer U) => unknown): unknown;
} ? U : T;

答案 5 :(得分:1)

ts-toolbelt库具有PromiseOf

import {C} from 'ts-toolbelt'

const promise = new Promise<string>((res, rej) => res('x'))    
type test0 = C.PromiseOf<typeof promise>  // string

type test1 = C.PromiseOf<Promise<number>> // number

答案 6 :(得分:1)

我们可以通过查看 Promise 的 then 函数的参数来推断类型。

type PromisedString = Promise<string>;
type AwaitedPromisedString = Parameters<Parameters<PromisedString['then']>[0] & {}>[0];

const promisedString: PromisedString = Promise.resolve('sup');
const x: AwaitedPromisedString = await promisedString;
// assignment succeeds!
const y: string = x;

我们可以概括为一个实用程序类型:

type Awaited<T extends Promise<unknown>> = Parameters<Parameters<T['then']>[0] & {}>[0];
const promisedString: Promise<string> = Promise.resolve('sup');
const x: Awaited<typeof promisedString> = await promisedString;
const y: string = x;

让我们分解一下:

Promise<string>['then'] 一个接受回调的函数。让我们获取该函数的参数。
Parameters<Promise<string>['then']>[0] then 的第一个参数:它的回调。这是可选的,因此我们需要将联合范围缩小到仅真实类型。
Parameters<Promise<string>['then']>[0] & {} 回调本身。这是一个函数;让我们获取它的参数。
Parameters<Parameters<Promise<string>['then']>[0] & {}>[0] 回调的第一个参数:Promise 解析的值。这就是我们要找的。

鉴于上述条件类型,也许这个答案似乎是多余的,但我发现它对于解决 JSDoc 中的 Promises 很有用,在那里(我认为)不可能定义新的实用程序类型,但 可以使用现有的:

/** @param {Parameters<Parameters<ReturnType<import('box2d-wasm')>['then']>[0] & {}>[0]} box2D */
export const demo = box2D => {
};

答案 7 :(得分:0)

Promise类型中没有任何内容允许访问或提取其值的类型。你必须找到一种使用类型推断的间接方式。

一个选项是将promiseOne作为独立函数作为类构造函数的参数传递,并且类本身是通用的。然后编译器能够从promise类型中推断出值类型:

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

class C<T> {
    constructor(private p: () => Promise<T>) {
        p().then(value => this.pValue = value)
    }

    pValue: T | undefined = undefined;
}

const c = new C(promiseOne); // at compile time, typeof c is C<number>