如何将现有属性装饰器转为参数装饰器以适配类属性简写?
适配class-transformer的@Type装饰器为参数装饰器的最简方案
问题背景
想要将class-transformer的@Type属性装饰器用于构造函数的属性简写参数中,把原有代码:
class Test { @Type(() => SomeClassType) public prop1: SomeClassType; constructor(prop1: SomeClassType) { this.prop1 = prop1; } }
简化为:
class Test { constructor(@Type(() => SomeClassType) public prop1: SomeClassType) {} }
但@Type仅支持属性装饰器,无法直接作用于构造函数参数(即使是带public修饰符的属性简写),需要一个适配方案将属性装饰器转为参数装饰器。
最简适配方案
可以创建一个简单的包装器装饰器,利用TypeScript的反射元数据,把参数装饰器的调用映射到对应的类属性上,复用原@Type装饰器的逻辑:
import { Type, type TypeOptions } from 'class-transformer'; import 'reflect-metadata'; export function TypeParam(typeFunction: () => Function, options?: TypeOptions) { return function (target: any, propertyKey: string | symbol, parameterIndex: number) { // 获取构造函数的参数名称数组 const paramNames = Reflect.getMetadata('design:paramnames', target) || []; const propName = paramNames[parameterIndex]; // 直接调用原@Type装饰器,将其应用到对应的类属性上 Type(typeFunction, options)(target, propName); }; }
使用方式
现在可以直接在构造函数的属性简写参数上使用这个包装后的装饰器:
class Test { constructor(@TypeParam(() => SomeClassType) public prop1: SomeClassType) {} }
原理说明
- 借助
reflect-metadata库的design:paramnames元数据,获取构造函数参数的名称,这个名称和属性简写生成的类属性名一致。 - 拿到属性名后,直接调用原
@Type装饰器,把它当作属性装饰器作用于类的对应属性上,完全复用原装饰器的逻辑。 - 注意需要确保项目中已经安装并引入了
reflect-metadata,同时tsconfig.json中开启了emitDecoratorMetadata选项。
内容的提问来源于stack exchange,提问作者Phelizer
相关产品推荐
相关产品推荐

