TypeScript 装饰器入门核心用法

一、什么是装饰器?

装饰器就是普通函数 ,用 @装饰器名 贴在类、方法、属性上,作用就是给被装饰的东西加额外功能,仅此而已。

二、最基础用法:类装饰器

直接贴在类上,函数唯一参数是被装饰类的构造函数,最简单的例子:给类加静态属性。

typescript 复制代码
// 定义装饰器函数:给类加版本号
function addVersion(target) {
  target.version = '1.0.0'; // 给类挂载静态属性
}

// 用@贴在类上,完成装饰
@addVersion
class MyClass {}

// 直接使用装饰器加的属性
console.log(MyClass.version); // 输出:1.0.0

核心逻辑:@addVersion 等价于 addVersion(MyClass),把类传给装饰器函数就行。

三、最常用用法:方法装饰器

贴在类的方法上,日常用得最多,函数有 3 个固定参数:不用死记含义,跟着案例用就会。

简单案例1:给方法加日志

执行方法时,自动打印"方法被调用了",不用在方法里写重复代码。

typescript 复制代码
// 方法装饰器:打印方法调用日志
function showLog(target, name, descriptor) {
  // 保存原方法
  const oldFn = descriptor.value;
  // 重写方法,加日志逻辑
  descriptor.value = function() {
    console.log(`【日志】${name}方法被调用了`);
    oldFn.apply(this); // 执行原来的方法
  };
}

class MyClass {
  // 装饰器贴在方法上
  @showLog
  sayHi() {
    console.log('hello TS');
  }
}

new MyClass().sayHi();
// 输出:【日志】sayHi方法被调用了 → hello TS

简单案例2:禁止方法被修改

让方法只读,不能被重新赋值,避免误改方法逻辑。

typescript 复制代码
// 方法装饰器:禁止方法修改
function noChange(target, name, descriptor) {
  descriptor.writable = false; // 设为不可写
}

class MyClass {
  @noChange
  fn() {
    console.log('不能改我');
  }
}

const obj = new MyClass();
obj.fn = () => {}; // 报错:无法分配到 "fn",因为它是只读属性

四、属性装饰器:给属性加默认值

贴在类的属性上,函数有 2 个参数,最简单的用法:给属性设置默认值,不用在构造函数里初始化。

typescript 复制代码
// 属性装饰器:设置默认值
function setDefault(val) {
  return function(target, name) {
    target[name] = val;
  };
}

class MyClass {
  // 贴在属性上,传默认值
  @setDefault('张三')
  name;

  @setDefault(20)
  age;
}

console.log(new MyClass().name); // 输出:张三
console.log(new MyClass().age); // 输出:20

五、装饰器工厂:给装饰器传参

想给装饰器传自定义参数(比如日志加前缀、默认值自定义),就写装饰器工厂------本质是「返回装饰器的函数」,写法超简单,看案例就会。

案例:带前缀的日志装饰器

让日志有自定义前缀,不用写多个装饰器函数。

typescript 复制代码
// 装饰器工厂:接收自定义前缀
function log(prefix) {
  // 返回真正的装饰器函数
  return function(target, name, descriptor) {
    const oldFn = descriptor.value;
    descriptor.value = function() {
      console.log(`【${prefix}】${name}方法执行了`);
      oldFn.apply(this);
    };
  };
}

class MyClass {
  // 传参使用:自定义前缀"接口请求"
  @log('接口请求')
  getData() {}

  // 传参使用:自定义前缀"操作"
  @log('操作')
  saveData() {}
}

new MyClass().getData(); // 输出:【接口请求】getData方法执行了
new MyClass().saveData(); // 输出:【操作】saveData方法执行了

六、必记规则:多个装饰器的执行顺序

一个类/方法上贴多个装饰器时,从下往上执行------谁离被装饰的东西近,谁先执行。

typescript 复制代码
// 定义两个简单装饰器
function A(target) {
  console.log('执行装饰器A');
  return target;
}
function B(target) {
  console.log('执行装饰器B');
  return target;
}

// B离类更近,先执行;A后执行
@A
@B
class MyClass {}

// 运行结果:先打印「执行装饰器B」,再打印「执行装饰器A」

等价理解:MyClass = A(B(MyClass)),先执行内层的 B,再执行外层的 A。

七、使用前提:开启TS配置

装饰器是 TS 实验性特性,必须在 tsconfig.json 里加一行配置,否则报错,就加这一个核心项就行:

json 复制代码
{
  "compilerOptions": {
    "experimentalDecorators": true, // 必须开启,启用装饰器
    "target": "ES5" // 项目基本配置,一般都有
  }
}
相关推荐
Live0000015 小时前
在鸿蒙中使用 Repeat 渲染嵌套列表,修改内层列表的一个元素,页面不会更新
前端·javascript·react native
柳杉15 小时前
使用Ai从零开发智慧水利态势感知大屏(开源)
前端·javascript·数据可视化
兆子龙15 小时前
从高阶函数到 Hooks:React 如何减轻开发者的心智负担(含 Demo + ahooks 推荐)
前端
狗胜15 小时前
测试文章 - API抓取
前端
三小河15 小时前
VS Code 集成 claude-code 教程:告别海外限制,无缝对接国内大模型
前端·程序员
jerrywus15 小时前
前端老哥的救命稻草:用 Obsidian 搞定 Claude Code 的「金鱼记忆」
前端·agent·claude
球球pick小樱花15 小时前
游戏官网前端工具库:海内外案例解析
前端·javascript·css
前端Hardy16 小时前
干掉 Virtual DOM?尤雨溪开始"强推" Vapor Mode?
vue.js·vue-router
用户605723748730816 小时前
AI 编码助手的规范驱动开发 - OpenSpec 初探
前端·后端·程序员