如何利用TypeScript泛型扩展函数返回值类型并添加新属性?
解决TypeScript泛型添加属性后的类型定义问题
你的问题核心是返回类型没有包含新增的children属性——原函数返回Array<T>,但T(继承自Src)并没有children字段,所以TypeScript无法推断出返回值有这个属性。
要解决这个问题,你需要:
- 定义一个交叉类型,把原输入类型
T和带有children的类型合并 - 修改函数的返回类型为这个交叉类型的数组
- 在函数内部赋值时,通过类型断言告诉TypeScript当前元素可以添加
children属性
具体实现代码
// src array const src = [ { id: 3, parentId: 2 }, { id: 2, parentId: 1 }, { id: 1 }, { id: 4 }, { id: 5, parentId: 4 }, { id: 6, parentId: 8 }, { id: 7, parentId: 9 }, { id: 7, parentId: 9, title: 'ssss' }, ]; interface Src { id: number; parentId?: number | string; title?: string; } // 定义带children的交叉类型,这里假设children是同类型的节点数组(适合树形结构) type NodeWithChildren<T> = T & { children: NodeWithChildren<T>[] }; function addChildren<T extends Src>(arr: T[]): NodeWithChildren<T>[] { // 这里以构建树形结构为例,你可以替换成自己的children赋值逻辑 return arr.map(item => ({ ...item, // 筛选当前节点的子节点 children: arr.filter(child => child.parentId === item.id) })) as NodeWithChildren<T>[]; } // 调用后,res的每个元素都会保留原类型属性,同时拥有children字段 const res = addChildren(src); // 此时TypeScript会提示res[0]有id、parentId、children等属性 console.log(res[0].children);
关键说明
- 交叉类型
NodeWithChildren<T>:通过T & { children: ... }将原类型的所有属性和新增的children属性合并,确保返回值的类型既保留原结构,又包含新属性。 - 类型断言:在
map返回时用as NodeWithChildren<T>[]告诉TypeScript,我们已经给每个元素添加了children,可以安全地将其视为交叉类型。 - 如果你的
children不是子节点数组,而是其他类型(比如单个对象),只需要修改NodeWithChildren里的children类型即可,比如{ children: YourChildrenType }。
直接修改原数组的写法
如果你不想创建新数组,而是直接修改原数组,代码如下:
function addChildrenDirectly<T extends Src>(arr: T[]): NodeWithChildren<T>[] { for (let i = 0; i < arr.length; i++) { // 类型断言允许我们给原对象添加children属性 (arr[i] as NodeWithChildren<T>).children = arr.filter(child => child.parentId === arr[i].id); } return arr as NodeWithChildren<T>[]; }
内容的提问来源于stack exchange,提问作者Eric-Guo
相关产品推荐
相关产品推荐

