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" 
相关推荐
夏天要喝冰可乐几秒前
我用 WorkBuddy 做了个「GitHub 考古所」:输入一个用户名,出土你的编程人格档案
前端·github
乘风gg5 分钟前
AI coding 时代最值钱的东西,软件工程(下)
前端·ai编程·claude
用户114818678948415 分钟前
虚拟滚动与无限滚动的完整心法
前端
核验笔记的老王15 分钟前
前端表单防呆实践:如何排查自动填充导致的提交失败?
前端
用户4061220811116 分钟前
Vue vs React 核心差异全对比
前端
李纲明20 分钟前
微信小程序 web-view 打开空白或提示未配置业务域名:校验文件、HTTPS 与跳转域名排查
前端·微信小程序·https·web-view·小程序开发·业务域名
涛涛ing26 分钟前
一个框架为了“不水合”,把HTML注释都删了
前端
计算机魔术师1 小时前
AI渗透框架3小时破云,中国黑客组织正在升级打法
前端
蒲公英内测分发1 小时前
智能手环出海测试,海外合作方分散在不同国家,Android 测试包怎么持续分发和更新?
android·前端·人工智能·测试工具·智能手表
朱涛的自习室1 小时前
高价软件已死,我让 AI 开启了「平替计划」(Day 7 / 7)
android·前端·github