为什么 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> {
我想将 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> {