You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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-

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 21:55:00