Как я могу заставить свой декоратор класса работать только на самом внешнем классе в цепочке наследования? - PullRequest
0 голосов
/ 24 октября 2018

Я использую class-validator декораторы для проверки классов данных, которые включают данные, поступающие извне моего приложения во время выполнения.Я хочу, чтобы мои классы подтвердили себя на примереЯ написал декоратор классов, чтобы легко добавить эту функциональность в классы.

import * as t from 'class-validator';

interface Class {
  new(...args: any[]): {};
}

export function autoValidate<T extends Class>(target: T) {
  return class extends target {
    constructor(...args: any[]) {
      super(...args);

      const errors = t.validateSync(this);

      if (errors.length > 0) {
        throw errors;
      }
    }
  };
}

Проблема с этим декоратором классов заключается в том, что когда наследование вступает в игру, когда класс и его предок оба украшаются этим декоратором.

@autoValidate
class Parent {
  @t.IsNumber()
  readonly age: number;

  @t.IsString()
  readonly name: string;

  constructor(age: number, name: string) {
    this.age = age;
    this.name = name;
  }
}

@autoValidate
class Child extends Parent {
  @t.IsBoolean()
  readonly happy: boolean;

  constructor(age: number, name: string, happy: boolean) {
    super(age, name);

    this.happy = happy;
  }
}

Когда создается экземпляр Child, валидатор выдаст ошибку в конструкторе Parent конструктора, когда super вызывается в конструкторе / декораторе Child, поскольку happy являетсяundefined.

Как я могу изменить свой декоратор так, чтобы он запускал свой проверочный код, только если this является экземпляром target, но не является потомком target?

1 Ответ

0 голосов
/ 24 октября 2018

Решение, основанное на идее Патрика Робертса, с дополнительной защитой от определения подкласса и забывания @autoValidate (что в противном случае вообще не привело бы к проверке):

import * as t from 'class-validator';

interface Class {
  new(...args: any[]): {};
}

const lastClassWithValidation = Symbol();
export function autoValidate<T extends Class>(target: T) {
  return class extends target {
    static [lastClassWithValidation] = target;
    constructor(...args: any[]) {
      super(...args);

      if ((<any>this.constructor)[lastClassWithValidation] === target) {
        const errors = t.validateSync(this);

        if (errors.length > 0) {
          throw errors;
        }  
      }
    }
  };
}
...