TypeScript中能否实现自实例化的getter属性?
在TypeScript中实现延迟加载且自动替换为实例属性的Getter
当然可以实现,下面是满足你需求的强类型解决方案——核心思路是第一次调用getter时创建实例,随后将该getter替换为普通实例属性,避免后续访问时重复执行初始化逻辑:
基础实现版本
interface PropInstance { data: string; } class MetadataHolder { get prop(): PropInstance { // 移除当前的getter定义,替换为实例属性 Object.defineProperty(this, 'prop', { value: { data: 'Here is the data' }, writable: true, enumerable: true, configurable: true }); console.log('Creating instance'); return this.prop; } } // 测试代码 const obj = new MetadataHolder(); console.log(obj.prop.data); // 输出 "Creating instance" 和 "Here is the data" console.log(obj.prop.data); // 直接输出 "Here is the data",不再触发初始化逻辑
多属性场景的优化方案(装饰器封装)
如果你的类有大量这类元数据属性,用装饰器封装可以避免重复代码,同时保持强类型:
// 定义延迟加载属性的装饰器 function lazyProperty<T, K extends keyof T>( target: T, propertyKey: K, descriptor: PropertyDescriptor ) { const originalGet = descriptor.get!; descriptor.get = function() { const value = originalGet.call(this); // 将getter替换为普通数据属性 Object.defineProperty(this, propertyKey, { value, writable: true, enumerable: true }); return value; }; descriptor.configurable = true; } // 示例实例类型 interface PropInstance { data: string; } interface AnotherMetaInstance { value: number; } class MetadataHolder { @lazyProperty get prop(): PropInstance { console.log('Creating prop instance'); return { data: 'Here is the data' }; } @lazyProperty get anotherMeta(): AnotherMetaInstance { console.log('Creating anotherMeta instance'); return { value: 42 }; } } // 测试代码 const obj = new MetadataHolder(); console.log(obj.prop.data); // 触发初始化,输出日志和数据 console.log(obj.prop.data); // 直接访问属性,无日志 console.log(obj.anotherMeta.value); // 触发初始化,输出日志和值 console.log(obj.anotherMeta.value); // 直接访问属性,无日志
原理说明
- 第一次访问getter时,执行初始化逻辑创建实例;
- 随后通过
Object.defineProperty将该属性重新定义为普通数据属性,覆盖原有的getter; - 后续访问时直接读取属性值,完全跳过getter的检查和初始化逻辑,兼顾了延迟加载和性能。
内容的提问来源于stack exchange,提问作者Adrian Brand
相关产品推荐
相关产品推荐

