如何用TypeScript装饰器实现类似Lombok的@Getters功能?
解决TypeScript装饰器实现Lombok @Getters的类型报错问题
需求说明
我希望复刻Java Lombok的@Getters功能,预期实现效果如下:
装饰器使用示例
@Getters() export class Example { private property: string; }
调用示例
const test = new Example(); console.log(test.getProperty()); // 期望无类型报错且正常调用
当前实现代码
我尝试通过TypeScript装饰器重写类定义来实现该功能,代码如下:
import { capitalize } from "lodash"; export const Getters = () => <T extends {new(...args:any[]):{}}>(constructor:T) => { return class extends constructor { constructor(...args: any[]) { super(...args); const props = Reflect.ownKeys(this); props.forEach((prop: string) => { const capitalizedKey = capitalize(prop); const methodName = `get${capitalizedKey}`; Reflect.defineProperty(this, methodName, { value: () => this[prop], configurable: false, enumerable: false }); }); } } }
遇到的问题
调用test.getProperty()时会触发类型报错:The X property does not exist on the X type.,但通过方括号语法test['getProperty']()可以正常执行。
解决方案
问题核心是TypeScript类型系统无法自动识别装饰器动态添加的方法,需要通过类型编程为类补充getter方法的类型定义:
1. 定义Getter类型映射工具
创建类型转换工具,将类的属性映射为对应的getter方法类型:
type GetterMethods<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] };
2. 修改装饰器的类型与实现
让装饰器返回的类同时继承原类并实现GetterMethods<T>,同时调整类型断言让TypeScript识别动态添加的方法:
import { capitalize } from "lodash"; // 属性转getter方法的类型定义 type GetterMethods<T> = { [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K] }; export const Getters = () => <T extends new (...args: any[]) => {}>(constructor: T) => { return class extends constructor implements GetterMethods<InstanceType<T>> { constructor(...args: any[]) { super(...args); const props = Reflect.ownKeys(this); props.forEach((prop) => { const propStr = prop as string; const capitalizedKey = capitalize(propStr); const methodName = `get${capitalizedKey}` as keyof GetterMethods<InstanceType<T>>; Reflect.defineProperty(this, methodName, { value: () => this[propStr], configurable: false, enumerable: false }); }); } } as T & (new (...args: ConstructorParameters<T>) => GetterMethods<InstanceType<T>>); };
3. 配置TypeScript编译选项
确保tsconfig.json中开启必要配置:
{ "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true, "strict": true, "lib": ["ESNext"] } }
验证效果
修改后,test.getProperty()不仅能正常运行,TypeScript也会正确识别该方法的类型,不再出现类型报错。
内容的提问来源于stack exchange,提问作者Ugo Evola
相关产品推荐
相关产品推荐

