在下面的代码中,getDocsWithIdThatWorks
之间的唯一区别是和 getDocsWithIdThatComplains
是他们传递给 Array.prototype.map
的回调.在一种情况下它是一个函数表达式,而在另一种情况下它是一个重载的泛型函数。在第一种情况下,TypeScript 完全理解并同意重载函数的返回类型。但是当将重载函数的引用直接作为参数传递给 Array.prototype.map
时, TypeScript 突然将返回类型推断为 DocumentWithId<unknown>
,尽管被映射的数组明确键入为 QueryDocumentSnapshot<T>
.为什么会这样?
interface DocumentSnapshot<T> {
id: string
data(): T | undefined
}
interface QueryDocumentSnapshot<T> extends DocumentSnapshot<T> {
data(): T
}
interface DocumentWithId<T> {
id: string
data?: T
}
interface QueryDocumentWithId<T> {
id: string
data: T
}
function withId<T>(document: QueryDocumentSnapshot<T>): QueryDocumentWithId<T>
function withId<T>(document: DocumentSnapshot<T>): DocumentWithId<T>
function withId<T>(document: DocumentSnapshot<T> | QueryDocumentSnapshot<T>): DocumentWithId<T> | QueryDocumentWithId<T> {
return {
id: document.id,
data: document.data(),
}
}
type Query<T> = () => Promise<QueryDocumentSnapshot<T>[]>
async function getDocsWithIdThatWorks<T>(query: Query<T>): Promise<QueryDocumentWithId<T>[]> {
const result = await query()
return result.map((d) => withId(d))
}
async function getDocsWithIdThatComplains<T>(query: Query<T>): Promise<QueryDocumentWithId<T>[]> {
const result = await query()
return result.map(withId)
}
最佳答案
这是 TypeScript 的一个已知设计限制;见microsoft/TypeScript#35501 . TypeScript 只能正确解析 overloaded functions 的调用签名当实际调用此类函数时。
当你写 d => withId(d)
, 你实际上是在调用 withId
参数类型为 QueryDocumentSnapshot<T>
, 编译器根据需要选择第一个调用签名。
但是当你刚刚通过 withId
至 map()
, 你没有调用 withId
因此不会发生正确的重载决议。相反,编译器只是“放弃”并选择最后一个签名。这会导致您看到的错误。
每当编译器必须推断涉及它不调用的重载函数的类型时,就会发生这种情况。我没有看到有关通用 类型推断的直接文档,但在 documentation about conditional type inference 中提到了它,它说:
When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types.
关于javascript - TypeScript 重载泛型函数的返回类型在与 Array.prototype.map 一起使用时被错误推断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73252877/