Typescript装饰程序+;反映元数据

Typescript装饰程序+;反映元数据,typescript,reflect-metadata,Typescript,Reflect Metadata,我正在使用属性装饰器字段,它将其“键”推送到字段反映元数据属性: export function Field(): PropertyDecorator { return (target, key) => { const fields = Reflect.getMetadata('fields', target) || []; if (!fields.includes(key)) { fields.push(key)

我正在使用属性装饰器
字段
,它将其“键”推送到
字段
反映元数据属性:

export function Field(): PropertyDecorator {
    return (target, key) => {
        const fields = Reflect.getMetadata('fields', target) || [];
        if (!fields.includes(key)) {
            fields.push(key)
        }
        Reflect.defineMetadata('fields', fields, target)
    }
}
然后我有一个抽象基类
表单
,它访问getter附件中的元数据:

abstract class Form {
    get fields() {
        return Reflect.getMetadata('fields', this) || [];
    }
}
到目前为止,我已经能够成功地使用它来区分表单字段和其他类属性。考虑这些类:

abstract class UserForm extends Form {
    @Field()
    public firstName: string

    @Field()
    public lastName: string

    get fullName() {
        return this.firstName + ' ' + this.lastName;
    }
}

class AdminForm extends UserForm {
    @Field()
    roles: string[]
}

const form = new AdminForm()
console.log(form.fields)
// ['roles', 'firstName', 'lastName']
当我将姐妹类定义为
AdminForm
-
MemberForm
时,就会出现问题。当有多个子类存在于
表单
中时,
字段
getter似乎返回所有字段:

class MemberForm extends UserForm {
    @Field()
    memberSince: Date;
}

const form = new AdminForm()
console.log(form.fields)
// ['roles', 'firstName', 'lastName', 'memberSince'] <--!!!
class MemberForm扩展了UserForm{
@字段()
成员自:日期;
}
const form=new AdminForm()
console.log(form.fields)

//['roles'、'firstName'、'lastName'、'memberSince']问题是
getMetadata
沿着原型链向下,并且总是返回在基类型上定义的内容(因为它首先被分配)。只有在添加新字段时,以及在获取字段时,才需要使用
getownmatadata
获取当前类的数组字段,而在获取字段时,则需要沿着属性链遍历以获取所有基类字段

这应该起作用:

import 'reflect-metadata'
export function Field(): PropertyDecorator {
  return (target, key) => {
      const fields = Reflect.getOwnMetadata('fields', target) || [];
      if (!fields.includes(key)) {
          fields.push(key)
      }
      Reflect.defineMetadata('fields', fields, target)
  }
}

abstract class Form {
  get fields() {
      let fields = []
      let target = Object.getPrototypeOf(this);
      while(target != Object.prototype) {
        let childFields = Reflect.getOwnMetadata('fields', target) || [];
        fields.push(...childFields);
        target = Object.getPrototypeOf(target);
      }
      return fields;
  }
}

abstract class UserForm extends Form {
  @Field()
  public firstName!: string

  @Field()
  public lastName!: string

  get fullName() {
      return this.firstName + ' ' + this.lastName;
  }
}

class AdminForm extends UserForm {
  @Field()
  roles!: string[]
}

const form1 = new AdminForm()
console.log(form1.fields) // ['roles', 'firstName', 'lastName']

class MemberForm extends UserForm {
  @Field()
  memberSince!: Date;
}

const form2 = new MemberForm()
console.log(form2.fields) // ["memberSince", "firstName", "lastName"]

有趣!如果我在属性装饰器上将
getMetadata
更改为
getownmatadata
,那么我将在
字段上获得
['roles']
。那么,你走上产业链是什么意思?哇!太棒了!谢谢!