如何为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; }
关键类型解析
FlatListToHierarchicalConfig- 泛型参数
TIdKey、TParentKey、TChildrenKey分别对应配置中的三个键名,默认值匹配函数的默认配置(id/parentId/children)。 - 约束配置参数的键名必须为字符串类型。
- 泛型参数
TreeNode- 使用
Omit<Item, TChildrenKey>移除原输入项中可能存在的childrenKey字段,避免类型冲突。 - 递归定义childrenKey字段的类型为
TreeNode<Item, TChildrenKey>[],确保树形结构的类型一致性。
- 使用
函数参数约束
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
相关产品推荐
相关产品推荐

