我有一个用于提取嵌套GraphQL数据的函数:
const data = {
cats: { edges: [ {node: cat1}, {node: cat2} ] },
dogs: { edges: [ {node: dog1}, {node: dog2}, {node: dog3} ] },
}
const extracted = extract<{ cats: CatType, dogs: DogType }>(data);
// extracted = {
// cats: [cat1, cat2], // CatType[]
// dogs: [dog1, dog2, dog3], // DogType[]
// }
然而,我很难正确地获得我的类型签名. 我想说的是"这个函数接受具有字符串键和类型值的接口参数,并返回具有相同键和相应类型数组值的对象".
换句话说,如果函数得到{ cats: nestedCats }
,它应该返回{ cats: CatType[] }
(即.cats: T['cat'])
).如果它得到了{ dogs: nestedDogs }
,它应该返回{ dogs: DogType[] }
、fish { fishes: FishType[] }
等等.如果它得到了多个类型,它应该返回一个包含所有类型的数组的对象.
现在我有一个签名:
export const extractNodesFromData = <T extends { [key: string]: any }> =>
然而,我有两个问题:
-
A)在我的函数中,当我迭代数据时,如何引用该数据的类型? 例如:
Object.entries(data).map(([key, value]) => // How do I type value?
Object.entries(data).map((([key, value: T[key]]) => // Doesn't work
-
B)我无法指定函数的返回类型:我不知道如何将我提供的类型(
{ cat: CatType, ...}
个)转换为相同的类型,但对于数组(即.{ cat: CatType[], ...}
).这就是该函数实际返回的内容.
Full Reproducible Example
这对实际问题没有任何增加,但有些人可能会发现看到其他(不相关)JS/TS很有帮助:
interface CatType {
id: string;
name: string;
catBreed: string;
}
interface DogType {
id: string;
name: string
dogBreed: string;
}
const extractNodes = <T>(data): T[] =>
data?.edges?.map(({ node }) => node);
const extractNodesFromData = <T extends { [key: string]: any }> (data: any) =>
Object.entries(data).reduce(
(extracted, [key, value: T[key]]) => ({
...extracted,
[key]: extractNodes<T[key]>(value)
}),
{}
)