TypeScript装饰器示例

引自 https://www.tslang.cn/docs/handbook/decorators.html

类装饰器

/**
 * 
 * @param constructor 构造函数
 * @returns 如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明
 */
function classDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
  return class extends constructor {
    newProperty = "new property";
    hello = "override";
  };
}

@classDecorator
export class Greeter {
  property = "property";
  hello: string;
  constructor(m: string) {
    this.hello = m;
  }
}

方法装饰器

/**
 *
 * @param value 传进来的参数
 * @returns
 */
function enumerable(value: boolean) {
  /**
   * @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
   * @param propertyKey 成员的名字(函数名)
   * @param descriptor 成员的属性描述符(
   *  configurable: true
      enumerable: false
      value: ƒ greet()
      writable: true
   * )
   */
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.enumerable = value;
  };
}

export class Greeter {
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }

  @enumerable(false)
  greet() {
    return "Hello, " + this.greeting;
  }
}

访问器装饰器

function configurable(value: boolean) {
  /**
   * @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
   * @param propertyKey 成员的名字(属性名)
   * @param descriptor 成员的属性描述符(
   *  configurable: true
      enumerable: false
      get: ƒ ()
      set: undefined
    )
   */
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    descriptor.configurable = value;
  };
}

export class Point {
  private _x: number;
  private _y: number;
  constructor(x: number, y: number) {
    this._x = x;
    this._y = y;
  }

  @configurable(false)
  get x() {
    return this._x;
  }

  @configurable(false)
  get y() {
    return this._y;
  }
}

属性装饰器

// 这里用到了reflect-metadata(元数据)
// 相关介绍见 https://jkchao.github.io/typescript-book-chinese/tips/metadata.html
import "reflect-metadata";
// ES6引入的数据类型 表示独一无二的值,最大的用法是用来定义对象的唯一属性名
const formatMetadataKey = Symbol("format");
/**
 *
 * @param formatString 装饰器参数
 * @returns 元数据添加
 */
function format(formatString: string) {
  return Reflect.metadata(formatMetadataKey, formatString);
}

/**
 *
 * @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
 * @param propertyKey 成员的名字
 * @returns 元数据读取
 */
function getFormat(target: any, propertyKey: string) {
  /**
   * @param metadataKey A key used to store and retrieve metadata
   * @param target The target object on which the metadata is defined.
   * @param propertyKey The property key for the target. 
   */
  return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}

export class Greeter {
  // 为greeting属性添加元信息
  @format("Hello, %s")
  greeting: string;

  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    // 读取greeting的元信息
    let formatString = getFormat(this, "greeting");
    // 替换greeting元信息("Hello, %s")里的"%s"为greeting属性值
    return formatString.replace("%s", this.greeting);
  }
}

参数装饰器

@required装饰器添加了元数据实体把参数标记为必需的。
@validate装饰器把greet方法包裹在一个函数里在调用原先的函数前验证函数参数。

import "reflect-metadata";

const requiredMetadataKey = Symbol("required");

/**
 *
 * @param target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
 * @param propertyKey 成员的名字("greet")
 * @param parameterIndex 参数在函数参数列表中的索引(0)
 */
function required(target: Object, propertyKey: string | symbol, parameterIndex: number) {
  let existingRequiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyKey) || [];
  existingRequiredParameters.push(parameterIndex);
  Reflect.defineMetadata(requiredMetadataKey, existingRequiredParameters, target, propertyKey);
}

// 参照方法装饰器
function validate(target: any, propertyName: string, descriptor: PropertyDescriptor) {
  let method = descriptor.value;
  descriptor.value = function () {
    let requiredParameters: number[] = Reflect.getOwnMetadata(requiredMetadataKey, target, propertyName);
    if (requiredParameters) {
      for (let parameterIndex of requiredParameters) {
        if (parameterIndex >= arguments.length || arguments[parameterIndex] === undefined) {
          throw new Error("Missing required argument.");
        }
      }
    }

    return method!.apply(this, arguments);
  };
}

export class Greeter {
  greeting: string;

  constructor(message: string) {
    this.greeting = message;
  }

  @validate
  greet(@required name: string) {
    return name + " " + this.greeting;
  }
}

// 输出 hello world
console.log(new Greeter("world").greet("hello"));

实例

使用elementui的message,在删除前提示
参考
https://www.cnblogs.com/wenruo/p/11984558.html

// decorators.ts
import { MessageBox } from "element-ui";

export function confirmation(message: string) {
  return function (target: any, name: string, descriptor: PropertyDescriptor) {
    let oldValue = descriptor.value;
    descriptor.value = function (args: IArguments) {
      MessageBox.confirm(message, "提示")
        .then(oldValue.bind(this, args))
        .catch(() => {});
    };

    return descriptor;
  };
}
// test.vue
import { confirmation } from "./decorators";

@confirmation("此操作将永久删除该文件, 是否继续?")
private deleteFile(data: any) {
  console.log(data + "deleted");
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值