如何为使用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
相关产品推荐
相关产品推荐

