我假设这是我的用户错误,但是当我写下面的代码时,我期望返回类型是User[]
,但是TS似乎认为它是User[][]
,即使我调用了flatMap()
。我不确定我的泛型是否搞砸了什么,但是TS似乎没有发现结果将被扁平化一级。实际的输出是正确的。但与推断的类型不匹配。
type User = {
id: number
firstName: string
}
type UserResponse = {
items: User[]
nextCursor: number
hasNextPage: boolean
}
type InfiniteData<PageType> = {
pages: PageType[]
}
const data: InfiniteData<UserResponse> = {
pages: [
{
items: [
{id: 1, firstName: 'Bob'},
{id: 2, firstName: 'Alice'}
],
nextCursor: 1,
hasNextPage: false
}
]
}
function useInfiniteData<TData, TValue>(
data: InfiniteData<TData>,
selectFn: (page: TData) => TValue
) {
return data.pages.flatMap((page) => {
// Returns a User[]
return selectFn(page)
})
}
// Expect User[] because flatMap flattens by one level,
// but TS thinks it's User[][]
const result = useInfiniteData(data, (page) => page.items)
// Output:
// result = [{
// "id": 1,
// "firstName": "Bob"
// }, {
// "id": 2,
// "firstName": "Alice"
// }]
这里是一个TSPlayground链接,如果这有助于调试。感谢任何建议!
1条答案
按热度按时间mwkjh3gx1#
现在的情况是,Typescript从函数的声明中推断出函数的返回类型,它不是在每个调用点推断出不同的返回类型,而是有一个通用的返回类型,然后在每个调用点通过插入该调用点的类型参数来实现。
函数的返回类型被推断为
TValue[]
,因为你用参数selectFn
调用flatMap
,它返回TValue
。仅仅看一下函数声明,Typescript就无法知道TValue
是数组类型,实际上签名也不要求它是数组类型。也许聪明的编译器可以推断TValue extends (infer U)[] ? U[] : TValue[]
为返回类型。或者类似的东西,但是flatMap
没有具有这样的签名的重载,并且Typescript在推理期间没有发明新的条件类型。然后在调用点,参数
TValue
被推断为User[]
,因为selectFn
参数返回的是User[]
,因此返回类型TValue[]
最终为User[][]
,这不是您想要的。最简单的解决方案是声明
selectFn
返回值或数组:Playground链接