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

TypeScript递归映射对象属性类型:实现层级属性路径生成函数

实现类型安全的嵌套路径构建器

嘿,这个类型安全的嵌套路径构建需求我太熟悉了!刚好可以用TypeScript的泛型和条件类型完美实现,每次调用都严格限制只能选当前层级对象的合法键,还能自动把路径累积起来。下面是我整理的可行方案,完全符合你的需求:

核心思路

我们需要一个路径构建器,它能:

  • 追踪当前操作的对象类型,确保每次调用只能传入该类型的合法键
  • 自动累积已选择的路径
  • 最后通过path属性返回完整的路径数组

利用TypeScript的泛型可以精准约束每一步的键类型,再通过闭包来保存路径的状态,就能实现这个功能。

完整代码实现

// 定义路径构建器的核心接口,泛型T是当前层级的对象类型,P是已累积的路径数组类型
interface PathBuilder<T, P extends string[]> {
  // 下一次调用时,只能传入当前类型T的键,同时更新路径和当前类型
  <K extends keyof T>(key: K): PathBuilder<T[K], [...P, K & string]>;
  // 只读属性,返回完整的路径数组
  readonly path: P;
}

// 重载path函数,支持两种调用方式:直接传初始键,或者先初始化再链式调用
function path<T>(initialKey: keyof T): PathBuilder<T[keyof T], [keyof T & string]>;
function path<T>(): PathBuilder<T, []>;
function path<T>(initialKey?: keyof T): any {
  // 用闭包保存当前路径
  const currentPath: string[] = initialKey ? [initialKey as string] : [];

  // 构建器函数,每次调用添加新键并返回自身
  const builder = <K extends keyof any>(key: K): any => {
    currentPath.push(key as string);
    return builder;
  };

  // 给构建器添加只读的path属性,返回路径副本避免外部修改
  Object.defineProperty(builder, 'path', {
    get: () => [...currentPath],
    enumerable: true
  });

  return initialKey ? builder : builder;
}

使用示例与类型验证

先把你的接口定义放进来:

interface Model { bla: Child1; bwap: string; }
interface Child1 { blu: Child2[]; }
interface Child2 { whi: string; }

按照你的需求调用:

let mapper = path<Model>("bla")("blu");
let myPropertyPath = mapper.path; // 类型为["bla", "blu"],实际值也是这个数组

类型安全验证

TypeScript会自动检查每一步的键是否合法:

  • 如果尝试传入Model不存在的键,比如path<Model>("invalidKey"),会直接报错
  • 如果在"bla"之后传入Child1不存在的键,比如path<Model>("bla")("invalidKey"),同样会报错

甚至支持更深层级的嵌套,比如访问数组元素的属性:

let deepMapper = path<Model>("bla")("blu")("0")("whi");
console.log(deepMapper.path); // 输出 ["bla", "blu", "0", "whi"]

这个方案完全满足你的要求,而且类型约束非常严格,能在编译期就避免路径错误。

内容的提问来源于stack exchange,提问作者Timothy Degryse

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 10:03:16