You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为GraphQL嵌套数据提取函数编写正确的TypeScript类型签名

解决GraphQL嵌套数据提取函数的TypeScript类型签名问题

需求回顾

我们需要实现一个函数,接收包含GraphQL风格嵌套结构的对象(每个属性值为带edges的连接对象),返回键名相同、值为对应节点类型数组的对象。例如输入{ cats: { edges: [...] } },输出{ cats: CatType[] }。


问题解决步骤

1. 定义GraphQL连接结构的通用类型

先统一约束GraphQL连接的结构,方便后续类型推导:

type GraphQLConnection<T> = { edges: Array<{ node: T }> };

2. 解决返回类型问题(问题B)

通过映射类型将输入对象的每个属性转换为对应节点的数组类型:

type ExtractConnectionNodes<T extends Record<string, GraphQLConnection<any>>> = {
  [K in keyof T]: T[K]['edges'][number]['node'][]
};

这个类型会遍历输入对象T的所有键K,提取对应连接结构里的node类型,再包装成数组。

3. 修复单个连接的节点提取函数

给extractNodes添加正确的类型约束,确保它只接收符合GraphQL连接结构的参数:

const extractNodes = <T>(data: GraphQLConnection<T> | undefined): T[] => {
  return data?.edges?.map(({ node }) => node) || [];
};

4. 解决遍历中的值类型问题(问题A)

给extractNodesFromData的参数指定正确的泛型约束,让TypeScript能自动推导Object.entries中value的类型,同时通过类型断言初始化reduce的累加器:

const extractNodesFromData = <T extends Record<string, GraphQLConnection<any>>>(
  data: T
): ExtractConnectionNodes<T> => {
  return Object.entries(data).reduce((extracted, [key, value]) => {
    return {
      ...extracted,
      [key]: extractNodes(value)
    };
  }, {} as ExtractConnectionNodes<T>);
};

这里data被约束为Record<string, GraphQLConnection<any>>,所以value会自动推导为对应键的GraphQLConnection<T>类型,无需手动指定T[key]。


完整可运行代码

interface CatType {
  id: string;
  name: string;
  catBreed: string;
}

interface DogType {
  id: string;
  name: string;
  dogBreed: string;
}

// 定义GraphQL连接结构的通用类型
type GraphQLConnection<T> = { edges: Array<{ node: T }> };

// 定义返回类型的映射类型
type ExtractConnectionNodes<T extends Record<string, GraphQLConnection<any>>> = {
  [K in keyof T]: T[K]['edges'][number]['node'][]
};

// 提取单个连接中的节点数组
const extractNodes = <T>(data: GraphQLConnection<T> | undefined): T[] => {
  return data?.edges?.map(({ node }) => node) || [];
};

// 批量提取多个连接中的节点数组
const extractNodesFromData = <T extends Record<string, GraphQLConnection<any>>>(
  data: T
): ExtractConnectionNodes<T> => {
  return Object.entries(data).reduce((extracted, [key, value]) => {
    return {
      ...extracted,
      [key]: extractNodes(value)
    };
  }, {} as ExtractConnectionNodes<T>);
};

// 示例使用
const cat1: CatType = { id: '1', name: 'Mimi', catBreed: 'Persian' };
const cat2: CatType = { id: '2', name: 'Luna', catBreed: 'Siamese' };
const dog1: DogType = { id: '3', name: 'Buddy', dogBreed: 'Labrador' };
const dog2: DogType = { id: '4', name: 'Max', dogBreed: 'German Shepherd' };
const dog3: DogType = { id: '5', name: 'Charlie', dogBreed: 'Poodle' };

const data = {
  cats: { edges: [{ node: cat1 }, { node: cat2 }] },
  dogs: { edges: [{ node: dog1 }, { node: dog2 }, { node: dog3 }] },
};

const extracted = extractNodesFromData(data);
// extracted类型为:{ cats: CatType[], dogs: DogType[] }
console.log(extracted);

内容的提问来源于stack exchange,提问作者machineghost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 16:38:16