Typescript属性装饰器自动添加到原型

时间:2017-09-27 03:36:37

标签: typescript typescript-decorator

我想为属性创建一个装饰,允许我自动添加属性而无需将其写入构造函数。我是Java / Type脚本的新手,所以我希望我没有这么糟糕。我似乎无法做到这一点,这就是我到目前为止所做的......

目标是通过以下方式:

class A {
  @uuid
  'property': string;
  'another': string;
}

function uuid(target: any, key: string): void {
  Reflect.defineMetadata('isUuid', true, target, key);
}

我以后可以使用A的构造函数new () => Object来获取所有属性的列表以及它们是否为UUID。我认为这看起来像是:

Object.keys(A).forEach(key => {
  console.log(`[${key}].isUuid? ${Reflect.getMetadata('isUuid', A, key) === true}`);
});

希望产生类似的东西:

[property].isUuid? true
[another].isUuid? false

作为备注,如果我将班级A更改为:

class A {
  constructor() {
    this.property = undefined;
    this.another = undefined;
  }
  @uuid
  'property': string;
  'another': string;
}

我可以让它工作,但我必须创建一个A的实例才能获取密钥并获取这些密钥的元数据。

1 个答案:

答案 0 :(得分:0)

如果您需要访问每个房产,您将需要装饰每个房产。由于reflect-metadata API不允许您枚举对象上使用的targetKey,因此您应该将元数据存储在对象本身上。

首先,定义要为每个属性记录的信息类型。到目前为止,还有isUuid

interface DbPropInfo {
  isUuid: boolean; 
  // other stuff
}

每条信息都有一个默认值,因此装饰器注释可以简洁:

const defaultDbPropInfo: DbPropInfo = {
  isUuid: false 
}

我们希望将元数据存储为一个对象,其对象的键与类的属性键相同,其值是我们为这些属性设置的DbPropInfo。这是该对象的类型:

interface DbProps {
  [k: string]: DbPropInfo;
}

现在是装饰者:

const dbPropsKey = 'dbProps';

function dbProp(info?: Partial<DbPropInfo>) {
  return function(target: any, key: string): void {
    if (!Reflect.hasMetadata(dbPropsKey, target)) {
      Reflect.defineMetadata(dbPropsKey, {}, target);
    }
    const dbProps: DbProps = Reflect.getMetadata(dbPropsKey, target);
    dbProps[key] = Object.assign({}, defaultDbPropInfo, info);
  }
}

获取装饰数据:

function getDbProps(ctor: { prototype: any }): DbProps | undefined {
  return Reflect.getMetadata(dbPropsKey, ctor.prototype);
}

最后,我们可以在你的课上尝试:

class A {
  @dbProp({ isUuid: true }) property: string;
  @dbProp() another: string;
}

让我们看看它是否有效:

console.log(JSON.stringify(getDbProps(A)));
// { 
//   "property": {"isUuid": true},
//   "another": {"isUuid": false}
// }

这对你有用吗?