无法使用类验证器在父类的构造函数内部进行验证

nik*_*k2o 2 javascript node.js typescript class-validator

我想在对象构造函数中使用 validateSync,但无法将其与继承一起使用。

我有这样的事情:

import { IsNotEmpty, IsString, validateSync, validate } from 'class-validator';

class Animal {

    @IsNotEmpty()
    @IsString()
    public name: string;

    constructor(name: string) {
        this.name = name;
        this.validate() // this method calls validate of class Dog, since this is an instance of Dog
    }

    protected validate() {
        const errors = validateSync(this);
        if (errors.length > 0) {
            console.log("Animal validation error: ", errors)
        }
    }
}

class Dog extends Animal {

    @IsNotEmpty()
    @IsString()
    public breed: string;

    constructor(name: string, breed: string) {
        super(name);
        this.breed = breed
        this.validate()
    }

    protected validate() {
        const errors = validateSync(this);
        if (errors.length > 0) {
            console.log("Dog validation error: ", errors)
        }
    }

}

const dog = new Dog('Aaron', 'Golden Retriever')
Run Code Online (Sandbox Code Playgroud)

结果是:

Dog validation error:  [ ValidationError {
    target: Dog { name: 'Aaron' },
    value: undefined,
    property: 'breed',
    children: [],
    constraints:
     { isString: 'breed must be a string',
       isNotEmpty: 'breed should not be empty' } } ]
Run Code Online (Sandbox Code Playgroud)

当我调用 Dog 构造函数时,代码运行 Animal 类的 super() ,然后运行 ​​this.validate() 。此方法验证 Dog 的实例,并且由于 Animal 没有 Breed 属性,因此代码会抛出上述错误。

我不知道如何解决这个问题,也许将验证放在构造函数中并不是一个好主意。

有没有解决方法或更好的方法来做到这一点?

Ima*_*tas 6

您收到错误的原因不是因为Animal没有该breed属性(事实上它有,因为实例实际上是Dog),而是因为您在设置要验证的所有值之前调用了验证(其中之一)。另一件事是,您进行了两次验证,这听起来不正确。

class Dog extends Animal {
    constructor(name: string, breed: string) {
        super(name); // <-- validation gets called in the parent but you did't set the breed property yet
        this.breed = breed; 
        this.validate(); // <-- validation gets called for the second time, but this time it passes
    }
}
Run Code Online (Sandbox Code Playgroud)

由于super()必须是构造函数中的第一个语句,因此您无法使用当前模式来避免这种情况。

解决方案之一是避免调用validate()基类,让子类正确设置所有字段,然后才进行验证。

我没有发现在构造函数中验证所需属性有任何问题,因为您正在阻止创建状态无效的对象。但是,如果在创建对象时并不是绝对需要拥有所有值,我建议允许调用者决定何时进行验证:

const dog = new Dog('Aaron');
// do some stuff like determine the breed...
dog.breed = 'Golden Retriever';
// do some more stuff
const validationResult = dog.validate(); // did I succeed?
Run Code Online (Sandbox Code Playgroud)

另请注意,您似乎不需要validate()在父类和子类中声明相同的方法。