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

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);
}

关键改进点

  1. 定义NestedObject类型:明确允许对象的属性值为number或其他NestedObject,适配真实的嵌套结构。
  2. 简化getNestedProperty实现:用循环替代递归(递归逻辑也可保留,循环更直观),同时增加类型校验,确保最终返回数值。
  3. 调整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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 15:00:03