javascript - TypeScript 重载泛型函数的返回类型在与 Array.prototype.map 一起使用时被错误推断

标签 javascript typescript

在下面的代码中,getDocsWithIdThatWorks之间的唯一区别是和 getDocsWithIdThatComplains是他们传递给 Array.prototype.map 的回调.在一种情况下它是一个函数表达式,而在另一种情况下它是一个重载的泛型函数。在第一种情况下,TypeScript 完全理解并同意重载函数的返回类型。但是当将重载函数的引用直接作为参数传递给 Array.prototype.map 时, TypeScript 突然将返回类型推断为 DocumentWithId<unknown> ,尽管被映射的数组明确键入为 QueryDocumentSnapshot<T> .为什么会这样?

Playground link

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> , 编译器根据需要选择第一个调用签名。

但是当你刚刚通过 withIdmap() , 你没有调用 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/

相关文章:

javascript - 在 Meteor 中更新我的文档

javascript - JavaScript中直线和圆之间的碰撞检测

typescript - "Cannot invoke an object which is possibly ' 未定义 '"即使在确保它之后!== 未定义

javascript - 我可以在 javaScript 和 typeScript 中为 firebase 编写云函数吗?

javascript - 使用 jQuery 正则表达式精确匹配多个搜索词

javascript - Angular JS - 使用过滤器检查单个值

javascript - 使用 tsc 转译后, Node 无法找到具有非相对路径的所需模块

typescript - 当 Y 具有索引签名时,为什么我会得到 "Property ' X' does not exit on type 'Y'?

typescript - TypeScript 是否有 Null 条件运算符

javascript - vue 进入过渡无法正常工作