代码之家  ›  专栏  ›  技术社区  ›  nomadoda

Typescript decorators+反射元数据

  •  0
  • nomadoda  · 技术社区  · 6 年前

    我用的是一个房产装饰师 Field 把它的“钥匙”推到 fields

    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)
        }
    }
    

    然后我有一个抽象基类 Form

    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'] <--!!!
    

    这对我来说毫无意义。为什么 memberSince 字段出现在的实例上 ? 如何在不同的子类上定义不同的字段?

    0 回复  |  直到 6 年前
        1
  •  2
  •   Titian Cernicova-Dragomir    6 年前

    问题是 getMetadata getOwnMetadata 若要仅在添加新字段时获取当前类的数组字段,并且在获取字段时,需要遍历属性链以获取所有基类字段。

    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"]
    
    推荐文章