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

如何为使用Object.defineProperty的node函数编写TypeScript类型定义?

解决TypeScript中node函数的类型推断问题

你的判断没错,Object.defineProperty属于运行时动态添加属性的操作,TypeScript编译器无法自动追踪这类操作带来的类型变化,导致第二个循环里的c被推断为any。要解决这个问题,需要给node函数编写更精确的泛型类型定义,让编译器知道返回的对象包含原父对象的属性,同时包含所有子对象的属性。

修改后的完整代码

class Category {
  #title: string

  constructor(
    title: string,
  ) {
    this.#title = title
  }

  get title() {
    return this.#title
  }
}

// 用泛型C捕获children的具体键和类型,返回T与C的交叉类型
function node<T extends object, C extends Record<string, T>>(
  parent: T,
  children: C,
): T & C {
  for (const [slug, value] of Object.entries(children)) {
    Object.defineProperty(parent, slug, {
      get() {
        return value
      },
      enumerable: true,
      configurable: true,
    })
  }

  // 类型断言告知编译器最终返回的类型
  return parent as T & C
}

const categories = {
  pets: node(new Category('Pets'), {
    dishes: new Category('Pets dishes'),
  }),
  cloth: node(new Category('Cloth'), {
    accessories: new Category('Accessories'),
  }),
}

for (const [slug, category] of Object.entries(categories)) {
  console.log(slug, category) // string, Category

  for (const [s, c] of Object.entries(category)) {
    console.log(s, c) // string, Category(不再是any)
    console.log(c.title) // 可安全访问title属性,类型校验生效
  }
}

关键改进点

  • 新增泛型C:用来保留children参数的具体键名和对应类型,避免Record<string, T>丢失具体键信息的问题。
  • 交叉类型返回值:将返回类型设置为T & C,明确告知编译器返回的对象同时拥有原父对象(T)和子对象集合(C)的所有属性。
  • 类型断言:因为TypeScript无法自动识别Object.defineProperty对parent类型的修改,所以用as T & C手动确认最终类型。

这样修改后,第二个循环里的c会被正确推断为Category类型,保证了代码的类型安全。

内容的提问来源于stack exchange,提问作者Pavel Perevezencev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:07:12