为什么 Typescript 认为 async/await returns 是一个包含在承诺中的值?

Why does Typescript think async/await returns a value wrapped in a promise?

我想将 promise 链重构为 async/await,但 Typescript 抱怨输入错误。

TS2322:Type 'IHttpPromiseCallbackArg< IResp >' is not assignable to type 'IResp'...

我认为 await 会 return 一个常规值,而不是承诺。我错了吗?如果是这样,我如何分配类型以便编译所需的代码?

我认为 await 会 return 与 .then 回调中的第一个参数相同的值。我错了吗?

旧代码:

handleSubmit(form) {
    const params = this.getParams(form);

    this.myAsyncRequest(params)
       .then((resp:IResp) => this.processResp(resp))
       .catch((e:IServerError) => this.handleError(e));
 }

需要的新代码:

async handleSubmit(form) {
    const params = this.getParams(form);

    try {
        const resp:IResp = await this.myAsyncRequest(params); //typing error with "const resp:IResp"
        this.processResp(resp);
    } catch (e:IServerError) {
        this.handleError(e);
    }
}

如果我删除 myAsyncRequest 中的 return 类型,所需的代码仍然会中断;我想 Typescript 直接从 AngularJS 库中推断出来。

myAsyncRequest(params:IParams):IHttpPromise<IResp> {
    return $http.post('blah', data);
}

如果我从 const resp 声明中删除 "IResp",processResponse 会抱怨 IHttp< IResp> 不等于 IResp...

processResp(resp:IResp) {
    //do stuff
}

包含 await 的行确实等待已解析的值 - 但由于函数本身是异步的(以允许所有等待),您会得到一个承诺。

示例...在下面的代码中,您可以将 x 用作普通数字(即使 delay returns 是一个承诺)并再次用于 y -所以你等待的所有东西都已解决,所以你可以像同步一样使用它。

看起来不像 returns 承诺的异步函数现在做到了。

这看起来令人困惑,因为它看起来 "invert the promises",但它所做的是将 then 移动到顶层(您可以让异步函数向下调用其他异步函数等上)。

function delay(ms: number) {
    return new Promise<number>(function(resolve) {
        setTimeout(() => {
            resolve(5);
        }, ms);
    });
}


async function asyncAwait() {
    let x = await delay(1000);
    console.log(x);

    let y = await delay(1000);
    console.log(y);

    return 'Done';
}

asyncAwait().then((result) => console.log(result));

你的问题"I thought await would return the same value as the first argument in the .then callback. Am I wrong?"。

不,你完全正确。但是你对 .then 回调中的第一个参数是什么是错误的。

您将 myAsyncRequest 定义为 return IHttpPromise<IResp>。但是 IHttpPromise<T> 被定义为继承 IPromise 的方式如下:

type IHttpPromise<T> = IPromise<IHttpPromiseCallbackArg<T>>;

因此,IHttpPromise<T> 是 return 一个 IHttpPromiseCallbackArg<T> 返回 T 类型的实际数据在 data 属性 的 IHttpPromiseCallbackArg<T>.

因此,我们在问题中看到的旧代码变体:

handleSubmit(form) {
    const params = this.getParams(form);

    this.myAsyncRequest(params)
       .then((resp:IResp) => this.processResp(resp))
       .catch((e:IServerError) => this.handleError(e));
 }
myAsyncRequest 定义为 return IHttpPromise.

时,

实际上不应该在 TypeScript 中没有错误地编译

如何解决这个问题:

async handleSubmit(form) {
    const params = this.getParams(form);

    try {
        const httpResp:IHttpPromiseCallbackArg<IResp> = await this.myAsyncRequest(params); 
        const resp: IResp = httpResp.data;
        this.processResp(resp);
    } catch (e:IServerError) {
        this.handleError(e);
    }
}

注意:在 angular 的最新类型定义中,类型 IHttpPromiseCallbackArg<T> 实际上称为 IHttpResponse<T>

也许在您的代码中,您将 IResp 定义为 IHttpResponse<Something>?那么你只是与旧名称IHttpPromiseCallbackArg发生冲突。然后从使用新名称的 DefinitelyTyped 获取最新的类型定义。而且您还必须将 myAsyncRequest 的定义更改为:

myAsyncRequest(params:IParams):IHttpPromise<Something> {