ts class 装饰器

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

function a() {
  console.log("调用 a");

  return function (target: any) {
    console.log("执行 a");
  };
}

function b() {
  console.log("调用 b");
  return function (target: any) {
    console.log("执行 b");
  };
}

@a()
@b()
class Ajanuw {}
λ ts-node index.ts
调用 a
调用 b
执行 b
执行 a

传递参数

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

@info({
  username: "ajanuw",
  age: 14,
  email: "123@sina.com",
})
class Ajanuw {
  constructor() {}
}
const a = <any>Ajanuw;
console.log(a.username, a.age, a.email);
console.log(Ajanuw.prototype.constructor["username"]); // ajanuw

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  阅读(861)  评论(0编辑  收藏  举报