TypeScript 装饰器

执行顺序

  1. 属性装饰器
  2. 方法装饰器
  3. 方法参数装饰器
  4. 类装饰器

如果同一个类型的装饰器有多个,总是先执行后面的装饰器。

less 复制代码
class NestedClass {
  @IsString()
  @exceedLength()
  name: string;

  constructor(props: any) {
    this.name = props.name;
  }
}

先执行exceedLength()再执行IsString()

类装饰器

可以为构造函数新增或修改变量或方法

typescript 复制代码
@reportableClassDecorator
class BugReport {
  constructor(t: string) {
    this.title = t;
    this._type = 'report';
  }
}


// 类装饰器
function reportableClassDecorator<T extends { new (...args: any[]): {}}>(constructor: T) {
  return class extends constructor {
    reportingURL = "http://www...";
    sayHello = () => {
        console.log('hello everyone');
    }
  }
}

interface BugReportV2 extends BugReport {
  reportingURL: string
  sayHello: () => void
}

const report = new BugReport("shanghai") as BugReportV2;

console.log(report.name);   // "http://www..." 
report.sayHello();					// "hello everyone"

属性装饰器

可以用于收集属性信息,也可以用来给类添加额外的方法和属性

通过元数据修改

更便捷的获取格式化数据

typescript 复制代码
import "reflect-metadata";
const formatMetadataKey = Symbol("format");

class BugReport {
  _type: string;
  title: string;
  @format("My name is %s")
  name: string = 'shenxin';

  constructor(t: string) {
    this.title = t;
    this._type = 'report';
  }

  introduceMyself() {
    const _tmpName = getFormat(this, 'name');
    return _tmpName.replace("%s", this.name);
  }
}

function format(formatString: string) {
  return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {
  return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}

interface BugReportV2 extends BugReport {
  reportingURL: string
  sayHello: () => void
}

const report = new BugReport("shanghai") as BugReportV2;

report.type = 'test';
report.name = "wangya";

console.log('name::: ', report.introduceMyself());  // "My name is wangya"

通过访问器修改

限制数据类型

typescript 复制代码
class NestedClass {
  @IsString()
  name: string;

  constructor(props: any) {
    this.name = props.name;
  }
}

function IsString() {
  return function (target: any, key: string) {
    let _key: string;
    Object.defineProperty(target, key, {
      get: () => _key,
      set: value => {
        if (typeof value !== 'string') {
          throw(`${key} must be a string`)
        }
        _key = value;
      }
    });
  }
}

const person = new NestedClass({
  name: 28,
});

console.log('person: ', person.name); // [ERR]: "name must be a string" 

方法装饰器

typescript 复制代码
class BugReport {
  _type: string;
  title: string;
  
  name: string = 'shenxin';

  constructor(t: string) {
    this.title = t;
    this._type = 'report';
  }
  
  @addHello
  getTitle() {
    return this.title;
  }
}


// 方法装饰器
function addHello(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    const _getTitle = descriptor.value;
    
    descriptor.value = function() {
      return `hello ${_getTitle.bind(this)()}`;
    }
}


const report = new BugReport("shanghai");

console.log(report.getTitle());     // "hello shanghai"

访问器装饰器

typescript 复制代码
class BugReport {
  _type: string;
  title: string;
  name: string = 'shenxin';

  constructor(t: string) {
    this.title = t;
    this._type = 'report';
  }
  

  @addTmp
  set type(value: string) {
    this._type = value;
  }
  get type() {
    return this._type;
  }
}

// 访问器装饰器
function addTmp(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
  const originSet = descriptor.set || function(){};

  descriptor.set = function(value: string) {
    // 获取方法参数
    return originSet.call(this, `this is ${value}`);
  }
}

const report = new BugReport("shanghai");

report.type = 'test';
console.log('report.type::: ', report.type);  // "this is test" 
相关推荐
宸翰1 小时前
解决 uni-app App 端 vue-i18n 占位符丢失:封装跨端可用的 tf 格式化方法
前端·vue.js·uni-app
systemPro1 小时前
光储充系统数据流全解析:PV / ESS / GRID 数据怎么流转,线损怎么算
前端
古茗前端团队3 小时前
急招!前端|测试|后端|产品(名额多,速来)
前端·后端·架构
Lsx_3 小时前
不只是 Prompt:用 Superpowers Skill 给 AI 编程装上工程化工作流
前端·ai编程·claude
小碗细面4 小时前
前端 Prompt 工程实战:如何搭建场景化 Prompt 库
前端·ai编程
阿瑞IT4 小时前
2026年 AI Agent 生产化落地全景:四大高频故障根因分析与工程解法
前端
木木剑光4 小时前
我开源了一个 React 组件库,沉淀了多个高频组件和实用 Hooks
前端·javascript·react.js
kyriewen4 小时前
DeepSeek API 高峰时段涨价 2 倍,便宜大碗的时代要结束了?
前端·ai编程·deepseek
Moment4 小时前
牛逼,NextJs 从 16.3 开始全面拥抱 Agent Native 🥰🥰🥰
前端·后端·面试