TypeScript装饰器元编程:用装饰器改写类与属性

2026-03-29 0 888

装饰器元编程:从入门到实战,完整掌握元数据反射与运行时类型操作

核心结论:装饰器是实现元编程最强大的特性,配合-库,可以在运行时读取、修改、添加类的元数据,实现依赖注入、验证、序列化、路由绑定等高级功能。本文基于 5.0+官方规范,提供可直接运行的完整示例和最佳实践。

1. 什么是装饰器元编程?

元编程是指编写能够操作、生成或转换其他代码的代码。装饰器本质上是一个函数,它接收目标类、方法、属性或参数的信息,并可以在编译时(实际是运行时)对这些成员进行修改、增强或添加元数据。

核心能力

在类定义时拦截并修改类的行为

给类、方法、属性附加自定义元数据(通过元数据反射API)

根据元数据在运行时执行逻辑(如自动验证、依赖注入)

启用装饰器.json):

{
  "": {
    "rs": true,      // 启用装饰器实验特性
    "a": true,       // 生成元数据(需要-)
    "": "ES5"                      // 或更高,推荐
  }
}

> 来源:官方文档 –

2. 五种装饰器类型完整解析

以下按执行顺序和参数结构说明,所有示例均可直接复制运行。

2.1 类装饰器

参数:

执行时机:类声明时,在类定义之后立即执行

返回值:如果返回一个新的构造函数,将替换原类的构造函数

// 基础示例:给类添加静态属性
 (: ) {
  .log(类 ${.name} 被创建);
  .. = new Date();
}
// 替换构造函数的示例
 <T  { new(...args: any[]): {} }>(: T) {
   class   {
     = new Date();
  };
}
@
@
class User {
  name: ;
  (name: ) { this.name = name; }
}

2.2 方法装饰器

参数

: (对于静态方法,是类的构造函数;对于实例方法,是类的原型对象)

: |

:

典型用途:日志、性能监控、权限校验、缓存

 (: any, : , : ) {
  const  = .value;
  .value = (...args: any[]) {
    .log(调用 ${},参数:, args);
    const  = .apply(this, args);
    .log(返回值:, );
     ;
  };
   ;
}
class  {
  @
  add(a: , b: ) {  a + b; }
}

2.3 属性装饰器

参数

: (同上)

: |

无法直接修改属性值,通常用于配合元数据记录字段类型或验证规则。

 (: any, : ) {
  // 记录哪些属性是必需的
  const  = . || [];
  .push();
  . = ;
}
class User {
  @
  name: ;
  age?: ;
}

2.4 参数装饰器

参数

:

: | (方法名)

: (参数在参数列表中的索引)

用途:配合方法装饰器,注入特定参数或标记参数用途。

 (: any, : , : ) {
  // 记录需要注入的参数位置
  const  = . || {};
  [] = true;
  . = ;
}
class  {
  (@ id: ) { / ... / }
}

2.5 装饰器工厂(带参数的装饰器)

通过外层函数接收自定义参数,返回真正的装饰器函数。

 Log(level: 'info' | 'error') {
    (: any, : , : ) {
    const  = .value;
    .value = (...args: any[]) {
      level;
       .apply(this, args);
    };
  };
}
class  {
  @Log('info')
  info() { / ... / }
}

3. 元数据反射:- 完整指南

装饰器本身只能操作代码结构,要真正实现元编程,必须配合元数据反射API- 是TC39提案的,官方推荐使用。

3.1 安装与导入

npm  -
 '-';  // 必须在入口文件最顶部导入一次

3.2 核心API

API 说明
.(, value, , ?) 定义元数据
.(, , ?) 读取元数据
.(, , ?) 检查是否存在元数据
.(, ?) 获取所有元数据键
.(, , ?) 删除元数据

3.3 自动类型元数据(a

TypeScript装饰器元编程

当启用a时,会自动生成以下元数据:

:type:属性或参数的类型

::方法参数的类型数组

::方法的返回类型

 '-';
class  {
  @.(':type', )
  name: ;
}
// 自动捕获类型
class Demo {
  (param: ):  {  1; }
}
const  = .(':', Demo., '');
.log(); // []
const  = .(':', Demo., '');
.log(); // 

4. 实战应用:三个完整的生产级示例

4.1 依赖注入容器(基于装饰器元编程)

 '-';
// 定义注入令牌
const  = ':token';
// 参数装饰器:标记需要注入的服务
 (token: ) {
   (: any, : , : ) => {
    const  = .(, , ) || [];
    [] = token;
    .(, , , );
  };
}
// 类装饰器:自动解析依赖
 (token: ) {
   (: any) => {
    .(':token', token, );
    // 保存构造函数供容器使用
     ;
  };
}
// 容器实现
class  {
    = new Map<, any>();
  (token: , : any) {
    this..set(token, );
  }
  <T>(: { new(...args: any[]): T }): T {
    const  = .(':', ) || [];
    const  = .(, ., '') || [];
    const args = .map((type: any, idx: ) => {
      const token = [idx];
      if (token) {
        const  = this..get(token);
         this.();
      }
       new type();
    });
     new (...args);
  }
}
// 使用示例
@('')
class  {
  () {  ['Alice', 'Bob']; }
}
class  {
  (@('')  : ) {}
  list() {  this..(); }
}
const  = new ();
.('', );
const ctrl = .();
.log(ctrl.list()); // ['Alice', 'Bob']

4.2 运行时验证框架

 '-';
const  = ':rules';
// 验证规则装饰器
 (: ) {
   (: any, : ) => {
    const rules = .(, , ) || [];
    rules.push({ type: '', value:  });
    .(, rules, , );
  };
}
 (: any, : ) {
  const rules = .(, , ) || [];
  rules.push({ type: 'email' });
  .(, rules, , );
}
// 验证执行器
 (: any): { valid: ; : [] } {
  const : [] = [];
  const  = .();
  const  = .keys();
  for (const prop of ) {
    const rules = .(, , prop) || [];
    const value = [prop];
    for (const rule of rules) {
      if (rule.type === '' &&  value === '' && value. < rule.value) {
        .push(${prop} 长度不能小于 ${rule.value});
      }
      if (rule.type === 'email') {
        const  = /^[^s@]+@([^s@.,]+.)+[^s@.,]{2,}$/;
        if (!.test(value)) .push(${prop} 不是有效的邮箱);
      }
    }
  }
   { valid: . === 0,  };
}
class  {
  @(3)
  : ;
  @
  email: ;
  (: , email: ) {
    this. = ;
    this.email = email;
  }
}
const form = new ('a', '');
.log((form)); 
// { valid: false, : [' 长度不能小于 3', 'email 不是有效的邮箱'] }

4.3 自动路由绑定(类似风格)

 '-';
const  = 'route:';
const  = 'route:';
 (: ) {
   (: any) => {
    .(, , );
  };
}
 Get(path: ) {
   (: any, : , : ) => {
    .(, { : 'GET', path }, , );
  };
}
 Post(path: ) {
   (: any, : , : ) => {
    .(, { : 'POST', path }, , );
  };
}
// 路由注册器
 (: any, app: any) {
  const  = .(, ) || '';
  const  = new ();
  const  = .;
  const  = .().(p => p !== '');
  for (const  of ) {
    const  = .(, , );
    if () {
      const  =  + .path;
      app..());
      .log(注册路由 ${.} ${} -&gt; ${.name}.${});
    }
  }
}
// 模拟
const  = {
  get: (path: , : ) => .log(GET ${path}),
  post: (path: , : ) => .log(POST ${path})
};
@('/users')
class  {
  @Get('/')
  list() {  ['user1']; }
  @Post('/')
  (body: any) {  { id: 1 }; }
}
(, );
// 输出:
// GET /users/ -> .list
// POST /users/ -> .

5. 常见问题与最佳实践

5.1 装饰器执行顺序

多个装饰器按以下顺序执行:

1. 参数装饰器(从后往前)

2. 方法装饰器

3. 属性装饰器

4. 类装饰器

同一目标上的多个装饰器:先执行靠近目标的装饰器工厂(从内到外),然后执行装饰器函数(从下到上)。

@
@
class Test {
  @
  @
  () {}
}
// 执行顺序:工厂 -> 工厂 -> 函数 -> 函数 ->  -> 

5.2 性能注意事项

装饰器在类定义时执行一次,不会影响实例化性能

元数据会存储在内存中,大量使用需注意内存占用

避免在装饰器内部执行重操作(如文件I/O、复杂计算)

5.3 与互操作

装饰器是实验特性,未来标准可能与当前实现不同。为确保兼容:

锁定版本(推荐5.x)

避免依赖未文档化的内部行为

对于生产项目,使用官方支持的-并关注提案进展

5.4 调试技巧

.json中启用"": true,然后在浏览器或Node中设置断点,可以进入装饰器函数内部调试。

# Node调试
node ---brk -r ts-node/ -r -/ your-file.ts

6. 总结与延伸学习

核心要点回顾

1. 装饰器是函数,分为五类:类、方法、属性、参数、工厂

2. - 是实现高级元编程的基石,提供运行时元数据读写

3. 启用a可自动捕获类型信息

4. 典型应用:依赖注入、验证、路由、序列化、日志、权限

下一步学习资源

– npm

TC39

开源框架源码:、、

立即动手:复制本文中的任一示例到你的项目中,修改装饰器逻辑,观察行为变化。只有亲手编写才能完全掌握装饰器元编程的精髓。

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

七爪网 行业资讯 TypeScript装饰器元编程:用装饰器改写类与属性 https://www.7claw.com/2827157.html

七爪网源码交易平台

相关文章