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

如何为flatListToHierarchical函数提供精准TypeScript类型定义?

为flatListToHierarchical函数编写TypeScript类型定义

要实现精准的类型约束,我们需要利用泛型和高级类型关联输入数组、配置参数与输出树形结构的类型。以下是完整的类型定义与实现:

类型定义与函数实现

// 配置参数的泛型类型,默认对应函数的默认键名
type FlatListToHierarchicalConfig<
  TIdKey extends string = 'id',
  TParentKey extends string = 'parentId',
  TChildrenKey extends string = 'children'
> = {
  idKey?: TIdKey;
  parentKey?: TParentKey;
  childrenKey?: TChildrenKey;
};

// 递归定义树形节点类型:移除原Item中的childrenKey字段,重新定义为子节点数组
type TreeNode<Item, TChildrenKey extends string> = Omit<Item, TChildrenKey> & {
  [K in TChildrenKey]: TreeNode<Item, TChildrenKey>[];
};

// 泛型函数实现
function flatListToHierarchical<
  Item,
  TIdKey extends string = 'id',
  TParentKey extends string = 'parentId',
  TChildrenKey extends string = 'children'
>(
  data: Array<
    Item & 
    // 必须包含idKey字段,类型为string/number
    { [K in TIdKey]: string | number } & 
    // parentKey字段可选,允许为undefined(函数会默认赋值为0)
    Partial<{ [K in TParentKey]: string | number | undefined }>
  >,
  {
    idKey = 'id' as TIdKey,
    parentKey = 'parentId' as TParentKey,
    childrenKey = 'children' as TChildrenKey
  }: FlatListToHierarchicalConfig<TIdKey, TParentKey, TChildrenKey> = {} as {}
): TreeNode<Item, TChildrenKey>[] {
  const tree: TreeNode<Item, TChildrenKey>[] = [];
  const childrenOf: Record<string | number, TreeNode<Item, TChildrenKey>[]> = {};

  data.forEach((item) => {
    const newItem = { ...item } as TreeNode<Item, TChildrenKey>;
    const { [idKey]: id, [parentKey]: parentId = 0 } = newItem;
    
    childrenOf[id] = childrenOf[id] || [];
    newItem[childrenKey] = childrenOf[id];
    
    if (parentId) {
      (childrenOf[parentId] = childrenOf[parentId] || []).push(newItem);
    } else {
      tree.push(newItem);
    }
  });

  return tree;
}

关键类型解析

  1. FlatListToHierarchicalConfig

    • 泛型参数TIdKey、TParentKey、TChildrenKey分别对应配置中的三个键名,默认值匹配函数的默认配置(id/parentId/children)。
    • 约束配置参数的键名必须为字符串类型。
  2. TreeNode

    • 使用Omit<Item, TChildrenKey>移除原输入项中可能存在的childrenKey字段,避免类型冲突。
    • 递归定义childrenKey字段的类型为TreeNode<Item, TChildrenKey>[],确保树形结构的类型一致性。
  3. 函数参数约束

    • data参数被约束为必须包含idKey字段,parentKey字段可选(允许为undefined,函数内部会默认赋值为0)。
    • 泛型参数Item自动推断自输入数组的元素类型,无需显式指定(除非需要更严格的约束)。

使用示例

自定义键名的情况

export interface BlockType {
  __typename?: string;
  key: number | string;
  parentKey: number | string;
  innerBlocks?: Array<BlockType | null>;
  name?: string;
}

const blocks: BlockType[] = [
  { key: '1', parentKey: '2', innerBlocks: [] }
];

// 调用时指定自定义键名,TypeScript自动推断返回类型
const hierarchicalBlocks = flatListToHierarchical(blocks, {
  idKey: 'key',
  parentKey: 'parentKey',
  childrenKey: 'innerBlocks'
});
// hierarchicalBlocks 的类型:TreeNode<BlockType, 'innerBlocks'>[]
// 等价于:Omit<BlockType, 'innerBlocks'> & { innerBlocks: TreeNode<BlockType, 'innerBlocks'>[] }[]

默认配置的情况

export interface BlockType {
  __typename?: string;
  id: number | string;
  parentId: number | string;
  children?: Array<BlockType | null>;
  name?: string;
}

const blocks: BlockType[] = [
  { id: '1', parentId: '2', children: [] }
];

// 使用默认配置,无需额外指定键名
const hierarchicalBlocks = flatListToHierarchical(blocks);
// 返回类型:TreeNode<BlockType, 'children'>[]

显式指定配置键类型(针对你提到的常量配置对象)

const myConfig = { idKey: "myKey", parentKey: 'myParentKey', childrenKey: "myChildrenKey" } as const;

interface MyItem {
  myKey: string;
  myParentKey?: string;
  myChildrenKey?: MyItem[];
  otherField: string;
}

const data: MyItem[] = [
  { myKey: '1', myParentKey: '2', otherField: 'test' }
];

// 显式指定泛型参数,让TypeScript严格匹配配置键
const tree = flatListToHierarchical<MyItem, typeof myConfig.idKey, typeof myConfig.parentKey, typeof myConfig.childrenKey>(data, myConfig);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 11:27:51