es7 class装饰器

文档http://es6.ruanyifeng.com/#docs/decorator

ts文档 https://www.tslang.cn/docs/handbook/decorators.html#class-decorators

当多个装饰器应用于一个声明上,从上至下调用,从下而上执行

function info(opt: {
    username: string;
    age: number;
    email: string;
}) {
    return function (klass: any) {
        klass.username = opt.username;
        klass.age = opt.age;
        klass.email = opt.email;
    }
}

@info({
    username: 'ajanuw',
    age: 14,
    email: '123@sina.com'
})
class Ajanuw {
    constructor() { }
}
const klass = (<any>Ajanuw);
console.log(klass.username, klass.age, klass.email);

es 的装饰器

let l = console.log

function klass(value) {
    return target => {
        // l(value) // api
        // l(target) // 对象
    }
}

function prop(value) {
    return function (target, key, des) { // target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
        // l(value) // username
        // l(target, key, des) // 对象,属性名,属性描述符
    }
}

function func(value) {
    return function (target, key, des) { // target 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
        // l(value) // function
        // l(key) // 函数名 show
        // l(des.value) // show函数, 可以改写
        // des.value = function(){
        //     l('hello')
        // }
    }
}

function Body(target) {
    // l( target ) // undefined
}

@klass('api')
class Ajanuw {
    @prop('username') name = 'ajanuw'

    @func('function')
    show(@Body body) {
        l(body)
    }
}

new Ajanuw().show()

重载构造函数

function classDecorator<T extends { new (...args: any[]): {} }>(
  constructor: T
) {
  return class extends constructor {
    newProperty = "new property";
    hello = "override";
  };
}

@classDecorator
class Greeter {
  constructor(public hello: string) {}
}
var g = new Greeter("world");
console.log(g.hello); // override

参数装饰器

import "reflect-metadata";

const requiredMetadataKey = Symbol("required");
const bodyMetadataKey = Symbol("body");

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 Body(key: string): any {
  return function (target: any, propertyKey: string, parameterIndex: number) {
    let existingRequiredParameters: any[] =
      Reflect.getOwnMetadata(bodyMetadataKey, target, propertyKey) || [];

    existingRequiredParameters.push({ parameterIndex, key });

    // 注入元数据
    Reflect.defineMetadata(
      bodyMetadataKey,
      existingRequiredParameters,
      target,
      propertyKey
    );
  };
}

function validate(
  target: any,
  propertyName: string,
  descriptor: TypedPropertyDescriptor<any>
) {
  let method = descriptor.value;

  // 重写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.");
        }
      }
    }

    // 获取目标对象上提供的元数据键的元数据值
    Reflect.getOwnMetadata(bodyMetadataKey, target, propertyName)?.forEach(
      (it: any) => {
        // 重写参数
        arguments[it.parameterIndex] = arguments[it.parameterIndex][it.key];
      }
    );

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

class Greeter {
  @validate
  greet(@required @Body("name") name: any): any {
    console.log("Hello " + name); // Hello xxxx
  }
}

const g = new Greeter();
g.greet({ name: "xxxx" });
posted @ 2018-04-24 22:20  Ajanuw  阅读(425)  评论(0编辑  收藏