Typescript async/await 无法确定正确的返回类型
Posted
技术标签:
【中文标题】Typescript async/await 无法确定正确的返回类型【英文标题】:Typescript async/await cannot determine correct return type 【发布时间】:2020-08-26 20:07:09 【问题描述】:我在 Typescript 中有以下基于 Promise 的方法:
filterByParams(
query: Aggregate<any[]>,
params: ParamsObject
): Promise<Aggregate<any[]>>
return this.findSomething(params)
.then<Aggregate<any[]>>((results: SomeResultType[]) =>
const matcher =
// ... using results to match something
;
return query.match(matcher);
);
该方法基本上根据另一个查询的结果将过滤器添加到(猫鼬)聚合中。
这工作得很好,Typescript 很高兴。
问题
如果我尝试将其转换为使用 async/await 模式,Typescript 开始抱怨。这是转换后的方法:
async filterByParams(
query: Aggregate<any[]>,
params: ParamsObject
): Promise<Aggregate<any[]>>
const results: SomeResultType[] = await this.findSomething(params);
const matcher =
// ... using results to match something
;
return query.match(matcher);
这次我在return ...
-line 上收到来自 Typescript 的编译错误,告诉我:
TS2322:类型“any[]”不可分配给类型“Aggregate”
Typescript 似乎无法从 query.match(matcher)
函数推断出正确的返回类型,甚至将其转换为 as Aggregate<any[]>
也无济于事。
如果我在基于 Promise 的方法中从 then(..)
函数中删除泛型类型,我会得到与使用 async/await 语法时大致相同的错误。
我正在使用 Typescript 3.7.2 版
谁能解释为什么会发生这种情况,以及是否有一种解决方法我仍然可以使用 async/await - 而不必将部分代码包装在 Promise 中?我觉得我已经尝试过明确地投射每种类型,但到目前为止没有运气。
更新 1
我已将有问题的代码简化为:
async filterByParams(
query: Aggregate<any[]>
)
return query;
虽然这个例子基本上什么都没做,但它仍然会导致编译错误。出于某种原因,async
关键字似乎只是打开了 Aggregate
类型。
将此与以下代码进行比较,类似,但不会导致错误:
declare class SomeGenericClass<T>
async filterByParams(
query: SomeGenericClass<any[]>
)
return query;
所以看起来这个问题在某种程度上特定于mongoose
提供的Aggregate
类型。
Here's a reproduction of the issue
【问题讨论】:
这可能与您使用的是any
有关。它完全打破了类型检查链。由于查询本身具有any
,因此当您使用query.match
时,它无法评估类型。不过,这只是一个假设。如果您在 TypeScript 操场上为我们提供最少的可重现代码会更好。
我尝试将 any 替换为显式类型,但我却得到了错误 Type 'SomeDocument[]' is not assignable to type 'Aggregate<SomeDocument[]>'
。稍后我将尝试在在线游乐场中重现它。
在 Promise-base 代码中,您执行 .then<Aggregate<any[]>>
,这实际上是手动类型转换返回类型。因此,当您删除它时,promise-base one 中也会引发错误。 async/await 基本代码中的等价物只是将其转换为as Aggregate<any[]>
。如果它引发错误,请尝试as any as Aggregate<any[]>
强制它。
findSomething
是如何定义的?可重复的示例会有所帮助
findSomething
方法似乎与它没有任何关系。我还不能在沙盒环境中重现该问题。
【参考方案1】:
虽然我还没有找到确切的解决方案,但我已经找到了解释。
我查看了mongoose implementation of the Aggregate
class,他们已将then
和catch
函数添加到Aggregate 类中,使其表现得像一个承诺。这将使 async/await 操作符将其视为一个承诺,因为它们将任何具有 then
-function 的对象视为一个承诺。这就是Aggregate
-class 从异步方法返回时似乎解包的原因。
对于手头的具体问题,作为一种解决方法,我只是将方法的异步部分移回调用代码。基本上就像我开始修补它之前一样。它并不完美,但它确实有效。
【讨论】:
以上是关于Typescript async/await 无法确定正确的返回类型的主要内容,如果未能解决你的问题,请参考以下文章
Async/Await - Typescript 和 ExpressJs
为啥 Typescript 认为 async/await 返回包装在承诺中的值?
实现一个 async/await (typescript 版)