为何不创建类实例就无法遍历其属性?对应解决方案有哪些?
为什么无法直接遍历类获取实例属性?
- 你在TypeScript类中写的
name: string、colour: string属于类型标注,仅在编译阶段做类型校验用,不会生成任何运行时代码,编译后会被完全清除,运行时根本不存在这些标记。 - 就算是纯JavaScript的类实例字段,也默认属于每个实例对象自身,既不会挂载到类构造函数(也就是你写的
Animal本身)上,也不会挂载到Animal.prototype原型对象上。只有当你调用new Animal()创建实例时,才会在新生成的实例对象上初始化这些字段。 - 你调用
Object.keys(Animal)拿到的是挂载在类构造函数上的静态属性,和实例属性完全是两个维度的内容,自然拿不到name、colour这些实例属性的key。
对应解决方案
要实现单一位置统一管理所有Animal属性,不需要重复定义接口和属性列表,可选以下方案:
方案1:用常量统一定义属性列表,反向推导类型
该方案属性定义只有一个数据源,修改、新增属性只需要改常量数组即可,完全不会出现类型和运行时属性不一致的问题。
// 统一定义所有属性,修改只需要改这里 const ANIMAL_PROPERTIES = ['name', 'colour'] as const; type AnimalProperty = typeof ANIMAL_PROPERTIES[number]; export class Animal { // 直接用推导出来的类型约束类属性,不需要重复写key [key in AnimalProperty]: string; constructor(init: string[]) { // 可以直接遍历属性列表赋值,避免手写漏项 ANIMAL_PROPERTIES.forEach((prop, index) => { this[prop] = init[index]; }); } } // 需要遍历属性的地方,直接用这个常量即可 for (const key of ANIMAL_PROPERTIES) { console.log(key); // 会依次输出 name、colour }
方案2:将属性列表挂载为类的静态属性
如果希望属性和类绑定更紧密,可以直接把列表定义为类的静态成员:
export class Animal { // 静态属性列表,全局可访问 static readonly PROPERTIES = ['name', 'colour'] as const; name: string; colour: string; constructor(init: string[]) { this.name = init[0]; this.colour = init[1]; // 注意示例代码中此处误写为color,会导致类型报错 } } // 遍历直接取静态属性即可 for (const key of Animal.PROPERTIES) { console.log(key); }
以上两种方案都可以同时满足类型校验和运行时遍历的需求,只有一个属性管理入口,不需要额外创建重复的interface。
内容的提问来源于stack exchange,提问作者Micha Brugger
相关产品推荐
相关产品推荐

