如何实现TypeScript装饰器的运行时条件触发?
实现延迟执行的装饰器逻辑:runTransformations函数方案
问题背景
TypeScript里装饰器默认在类定义阶段(构建时)就会执行,但我们希望@Transformer装饰器里的逻辑,只在调用runTransformations(classInstance)这个函数时才触发,参考class-transformer中@Expose装饰器在instanceToPlain调用时才生效的机制,需要实现这个runTransformations函数。
现有代码
类定义
class A { @Transformer() prop1: string }
初始装饰器实现
function Transformer(target: any, propertyKey: string) { return () => { console.log("ran"); } }
完整需求代码
import { plainToInstance } from 'class-transformer' function Transformer(target: any, propertyKey: string) { return () => { console.log("ran"); } } class A { @Transformer() prop1: string } const classInstance = plainToInstance(A, { prop1: "hello world" }) runTransformations(classInstance);
实现方案
核心思路和class-transformer一致:装饰器只负责收集元数据,真正的逻辑在runTransformations里读取元数据并执行。
1. 修改Transformer装饰器,收集延迟执行的逻辑
用TypeScript内置的Reflect API存储元数据,把每个属性的转换逻辑存到类的原型上:
import { plainToInstance } from 'class-transformer'; // 用唯一Symbol作为元数据的键,避免和其他元数据冲突 const TRANSFORMER_META_KEY = Symbol('transformer:functions'); function Transformer(target: any, propertyKey: string) { // 定义要延迟执行的逻辑 const transformFn = () => { console.log(`执行${propertyKey}的转换逻辑`); }; // 先读取当前类已经存储的转换函数数组,没有的话初始化空数组 let transformers = Reflect.getMetadata(TRANSFORMER_META_KEY, target) || []; // 把当前属性的转换函数和属性名存进去 transformers.push({ propertyKey, transformFn }); // 更新元数据 Reflect.defineMetadata(TRANSFORMER_META_KEY, transformers, target); }
2. 实现runTransformations函数
这个函数负责读取实例对应类的元数据,遍历执行所有收集到的转换逻辑:
function runTransformations(instance: any) { // 获取实例的类原型 const prototype = Object.getPrototypeOf(instance); // 读取存储的所有转换逻辑 const transformers = Reflect.getMetadata(TRANSFORMER_META_KEY, prototype); // 如果没有转换逻辑,直接返回 if (!transformers) return; // 遍历每个转换逻辑并执行 transformers.forEach(({ propertyKey, transformFn }) => { // 要是需要用到实例的属性值或者实例本身,也可以传进去,比如: // transformFn(instance[propertyKey], instance); transformFn(); }); }
3. 测试完整代码
class A { @Transformer() prop1: string; } const classInstance = plainToInstance(A, { prop1: "hello world" }); runTransformations(classInstance); // 此时才会输出:执行prop1的转换逻辑
原理说明
- 类定义阶段(装饰器执行时):只是把转换逻辑存到元数据里,不会执行任何业务逻辑
runTransformations调用阶段:从类原型中取出所有存储的转换函数,逐个执行,实现了延迟触发的效果- 这和
class-transformer的@Expose逻辑完全一致:装饰器做元数据收集,运行时函数负责读取元数据并执行逻辑
内容的提问来源于stack exchange,提问作者Islam Y-
相关产品推荐
相关产品推荐

