3

在我的项目中,我有一个具有许多属性的大对象。每个属性都有自己独特的验证,使用类验证器装饰器对其执行。该类的每个属性都被描述为一个 mixin。但是,我注意到在将 mixin 应用于基类时,只有最后传递的 mixin 才会运行其装饰器以进行验证。

例如,我们有:

export class Property {
  public async validate (): Promise<string[]> {
    const result = await validate(this)
    return result
  }
}

export class Name extends Property {
  @IsDefined()
  @IsString()
  @Length(5, 255)
  name: string
}

export class Description extends Property {
  @IsDefined()
  @IsString()
  @Length(16, 1000)
  description: string
}

每个属性,在单元测试时,都会正确地验证自己。

在创建从 mixins 继承的类时,我正在执行以下操作:

/**
 * Applies the mixins to a class. Taken directly from the Typescript documentation.
 */
function applyMixins (derivedCtor: any, baseCtors: any[]) {
  baseCtors.forEach(baseCtor => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
      Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name))
    })
  })
}

export class Foo {
  public async validate (): Promise<any> {
    const result = await validate(this)
    return result
  }
}

export interface Foo extends Name, Description { }
applyMixins(Foo, [Name, Description])

但是,在创建实例Foo并调用.validate实例时,我们只会收到描述错误。

是否有一些不同的方法来应用 mixins 以获得对所有混合属性的验证?

4

1 回答 1

2

这是因为 сlass-validator 使用原型来检测验证规则,我们需要将规则复制到派生 ctor 的原型中。

我们可以这样做:

/**
 * Applies the mixins to a class, but with class validator constraints.
 */
function applyMixinsWithValidators (derivedCtor: any, baseCtors: any[]) {
  const metadata = getMetadataStorage() // from class-validator

  // Base typescript mixin implementation
  baseCtors.forEach(baseCtor => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
      Object.defineProperty(derivedCtor.prototype, name, Object.getOwnPropertyDescriptor(baseCtor.prototype, name))
    })
  })

  baseCtors.forEach(baseCtor => {
    // Get validation constratints from the mixin
    const constraints = metadata.getTargetValidationMetadatas(baseCtor.prototype.constructor, '')

    for (const constraint of constraints) {
      // For each constraint on the mixin
      // Clone the constraint, replacing the target with the the derived constructor
      let clone = {
        ...constraint,
        target: derivedCtor.prototype.constructor
      }
      // Set the prototype of the clone to be a validation metadata object
      clone = Object.setPrototypeOf(clone, Object.getPrototypeOf(constraint))
      // Add the cloned constraint to class-validators metadata storage object
      metadata.addValidationMetadata(clone)
    }
  })
}

于 2020-05-14T07:50:04.820 回答