为啥 Typescript 认为 async/await 返回包装在承诺中的值?
Posted
技术标签:
【中文标题】为啥 Typescript 认为 async/await 返回包装在承诺中的值?【英文标题】:Why does Typescript think async/await returns a value wrapped in a promise?为什么 Typescript 认为 async/await 返回包装在承诺中的值? 【发布时间】:2018-03-29 15:07:14 【问题描述】:我想将一个 Promise 链重构为 async/await,但 Typescript 抱怨打字。
TS2322:类型“IHttpPromiseCallbackArg”不可分配给类型“IResp”...
我认为await
会返回一个常规值,而不是一个承诺。我错了吗?如果是这样,我如何分配类型以便编译所需的代码?
我认为 await 会返回与 .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
中的返回类型,所需的代码仍然会中断;我猜 Typescript 直接从 AngularJS 库中推断出来的。
myAsyncRequest(params:IParams):IHttpPromise<IResp>
return $http.post('blah', data);
如果我从 const resp 声明中删除“IResp”,则 processResponse 会抱怨 IHttp
processResp(resp:IResp)
//do stuff
【问题讨论】:
IHttpPromiseCallbackArg 类型不是承诺。这已经是函数调用的实际结果了。见definitelytyped.org/docs/angular-translate--angular-translate/… 我可以将我的问题改写为 - “我认为await
会返回与 .then
回调中的第一个参数相同的值。我错了吗?”
你是对的。但是你对 then 回调函数中第一个参数的类型是错误的。见definitelytyped.org/docs/angularjs--angular-route/interfaces/…
也许您对实际使用的类型定义错误。但是我们需要一个完整的工作示例来明确地说明这一点。
【参考方案1】:
包含await
的行确实等待解析的值 - 但由于函数本身是异步的(允许所有等待),你会得到一个承诺。
示例...在下面的代码中,您可以将x
用作纯数字(即使delay
返回一个承诺)并再次用于y
- 因此您等待的所有内容都已解决,因此您可以使用如果它是同步的,它更像你会的。
看起来不像它的异步函数返回了一个承诺,现在可以了。
这似乎令人困惑,因为它似乎“颠倒了承诺”,但它所做的是将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));
【讨论】:
所以说到底,我还是得在某个地方打电话给.then
?
您可能仍然必须在最顶部调用then
(在某些情况下,您将函数传递给其他东西,您不必这样做) .
反对票是怎么回事?有什么改进答案的建议吗?
这并没有回答似乎对函数返回的类型有误解的问题。 IHttpPromiseCallbackArg 类型不是提问者所假设的承诺。
我试图回答“我认为 await 会返回一个常规值,而不是一个承诺。我错了吗?”【参考方案2】:
您的问题“我认为 await 会返回与 .then 回调中的第一个参数相同的值。我错了吗?”。
不,你完全正确。但是您对 .then 回调中的第一个参数是错误的。
您将myAsyncRequest
定义为返回IHttpPromise<IResp>
。但是IHttpPromise<T>
被定义为继承IPromise
,方式如下:
type IHttpPromise<T> = IPromise<IHttpPromiseCallbackArg<T>>;
因此,IHttpPromise<T>
是一个返回 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
被定义为返回 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>
【讨论】:
以上是关于为啥 Typescript 认为 async/await 返回包装在承诺中的值?的主要内容,如果未能解决你的问题,请参考以下文章
Task.Run 在 ASP .NET MVC Web 应用程序中被认为是不好的做法吗?
Async / await vs then 哪个最适合性能?