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

Typescript property decorator auto-add to prototype

我想为属性创建一个装饰,这样我就可以自动添加 属性 而无需将其写入构造函数。我对 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

请注意,如果我将 class A 更改为:

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

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

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

首先,定义您希望为每个 属性 注释的信息类型。到目前为止,有 isUuid:

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

每条信息都有一个默认值有助于装饰器注释简洁:

const defaultDbPropInfo: DbPropInfo = {
  isUuid: false 
}

我们希望将元数据存储为一个对象,其键与 class 的 属性 键相同,其值为我们为这些设置的 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 上试用了:

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

让我们看看它是否有效:

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

这对你有用吗?