如何让TypeScript识别类中动态生成的带$前缀属性?
解决TypeScript识别类动态生成$前缀属性的问题
给定以下TypeScript类:
class Foo { bar = 1; constructor() { for (const [key, value] of Object.entries(this)) { Object.defineProperty(this, '$' + key, { value }); } this.$bar // <-- 如何让TypeScript识别这个属性? } }
要让TypeScript识别运行时动态创建的$bar这类前缀属性,同时解决你提到的“类定义及其方法内部无法让实例映射到目标类型”的问题,可以参考以下几种方案:
方案一:接口合并 + 映射类型(推荐)
利用TypeScript的接口合并特性,让类的实例类型自动包含所有$前缀的属性:
// 定义映射类型,给原类型的所有属性添加$前缀 type Prefixed<T> = { [K in keyof T as `$${K & string}`]: T[K] }; // 合并Foo接口,让它包含Prefixed<Foo>的所有属性 interface Foo extends Prefixed<Foo> {} class Foo { bar = 1; constructor() { for (const [key, value] of Object.entries(this)) { Object.defineProperty(this, '$' + key, { value }); } this.$bar; // TypeScript可以正常识别该属性 } testMethod() { console.log(this.$bar); // 类方法内部也能正常识别 } }
这种方式不需要额外的类型断言,类内部的this会自动具备所有$前缀属性的类型信息,同时外部实例也能正常访问这些属性。
方案二:类内部使用类型断言
如果不想用接口合并,可以在类内部将this断言为目标映射类型:
type U<T> = T & { [K in keyof T as `$${K & string}`]: T[K] }; class Foo { bar = 1; constructor() { // 将this断言为U<Foo>类型 const self = this as U<Foo>; for (const [key, value] of Object.entries(this)) { Object.defineProperty(self, '$' + key, { value }); } self.$bar; // 可以正常识别 } testMethod() { (this as U<Foo>).$bar; // 方法内部需要再次断言 } }
这种方式需要每次使用动态属性时手动断言,适合临时场景,不如方案一灵活。
方案三:手动声明动态属性
如果类的属性数量较少,可以直接在类内部用declare关键字手动声明动态属性的类型:
class Foo { bar = 1; // 手动声明$bar的类型 declare $bar: number; constructor() { for (const [key, value] of Object.entries(this)) { Object.defineProperty(this, '$' + key, { value }); } this.$bar; // TypeScript可以识别 } }
这种方式直观但扩展性差,当类的属性增多时需要逐个声明。
内容的提问来源于stack exchange,提问作者user26868532
相关产品推荐
相关产品推荐

