TypeScript递归类型实现遇编译错误,求解决方案
TypeScript递归类型实现与编译错误修复
问题场景
需要实现两个递归相关的函数:
getNestedProperty:递归获取对象嵌套属性的值sum:接收对象数组,对指定嵌套属性的值求和
原实现代码如下:
function getNestedProperty<T extends Record<string, T>, P extends keyof T>(obj: T, keys: string[]): T | T[P] { const nestedKeys = [...keys]; const nestedKey = nestedKeys.shift(); if (nestedKey !== undefined) { return getNestedProperty(obj[nestedKey], nestedKeys) as T; } else { return obj; } } export function sum<T extends number | Record<string, T>>(array: T[], keys?: string[]): number { const totalSum = array.reduce((accumulator: number, element: T) => { if (typeof element === 'number') { return accumulator + element; } if (keys === undefined) { throw new Error(`keys not passed in as an argument and type of Array is not number`); } return accumulator + +getNestedProperty(element, keys); }, 0); return totalSum; }
调用时触发编译错误:
const array = [ { a: { b: 1 } }, { a: { b: 3 } }, { a: { b: 5 } } ]; const actual = sum(array, ['a', 'b']); // 编译报错
错误信息:
Argument of type '{ a: { b: number; }; }[]' is not assignable to parameter of type '(number | Record<string, { a: { b: number; }; }>)[]'.
Type '{ a: { b: number; }; }' is not assignable to type 'number | Record<string, { a: { b: number; }; }>'.
Type '{ a: { b: number; }; }' is not assignable to type 'Record<string, { a: { b: number; }; }>'.
Property 'a' is incompatible with index signature.
Property 'a' is missing in type '{ b: number; }' but required in type '{ a: { b: number; }; }'.ts(2345)
错误原因
原代码的递归类型约束过于严格:
getNestedProperty中T extends Record<string, T>要求对象的所有属性值必须与对象本身类型完全一致,但实际场景中嵌套对象的层级类型是逐步变化的(比如外层是{a: {b: number}},内层是{b: number}),不符合该约束。sum函数的T extends number | Record<string, T>同样存在这个问题,导致传入的对象无法匹配类型约束。
解决方案
调整类型约束,使用更灵活的递归结构,允许嵌套对象的属性值为任意嵌套对象或最终的数值类型:
修正后的完整代码
// 定义通用嵌套对象类型,允许任意层级嵌套,最终值可以是number或其他嵌套对象 type NestedObject = { [key: string]: number | NestedObject }; function getNestedProperty(obj: NestedObject, keys: string[]): number { let current: NestedObject | number = obj; for (const key of keys) { if (typeof current !== 'object' || current === null) { throw new Error('Invalid nested key path'); } current = current[key] as NestedObject; } if (typeof current !== 'number') { throw new Error('Final value is not a number'); } return current; } export function sum(array: (number | NestedObject)[], keys?: string[]): number { return array.reduce((accumulator, element) => { if (typeof element === 'number') { return accumulator + element; } if (!keys) { throw new Error('Keys must be provided when array elements are objects'); } return accumulator + getNestedProperty(element, keys); }, 0); }
关键改进点
- 定义
NestedObject类型:明确允许对象的属性值为number或其他NestedObject,适配真实的嵌套结构。 - 简化
getNestedProperty实现:用循环替代递归(递归逻辑也可保留,循环更直观),同时增加类型校验,确保最终返回数值。 - 调整
sum函数的参数类型:直接使用(number | NestedObject)[],避免原约束的严格递归限制,同时增强错误处理逻辑。
测试验证
调用修正后的sum函数可正常通过编译:
const array = [ { a: { b: 1 } }, { a: { b: 3 } }, { a: { b: 5 } } ]; const actual = sum(array, ['a', 'b']); console.log(actual); // 输出9,符合预期
内容的提问来源于stack exchange,提问作者Joey
相关产品推荐
相关产品推荐

