最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Cannot use validate inside constructor of a parent class with class-validator - Stack Overflow

programmeradmin2浏览0评论

I want to use validateSync in object constructor, but I'm not able to use it with inheritance.

I've got something like this:

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

The result is:

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

When I call Dog constructor, the code runs super() and then this.validate() of the Animal class. This method validates an instance of Dog and since Animal doesn't have breed attribute, the code throw the error above.

I don't know how to solve this issue and maybe put validation inside constructors is not a good idea.

Is there a workaround or a better way to do that?

I want to use validateSync in object constructor, but I'm not able to use it with inheritance.

I've got something like this:

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

The result is:

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

When I call Dog constructor, the code runs super() and then this.validate() of the Animal class. This method validates an instance of Dog and since Animal doesn't have breed attribute, the code throw the error above.

I don't know how to solve this issue and maybe put validation inside constructors is not a good idea.

Is there a workaround or a better way to do that?

Share Improve this question asked Dec 24, 2018 at 12:16 nik2onik2o 932 silver badges11 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 6

The reason you get the error is not because Animal doesn't have the breed attribute (in fact it does, because the instance is actually Dog), but because you call the validation (one of them) before setting all the values you are validating. Another thing is, you do the validation twice which doesn't sound right.

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

And since super() must be the first statement in the constructor, you have no way of avoiding this with your current pattern.

One of the solutions would be to avoid calling validate() in the base class, let child classes set all the fields properly and only then do the validation.

I don't see anything wrong in validating required properties in constructor because you're preventing an object with invalid state being created. However, if it's not absolutely necessary to have all the values when the object is created, I'd suggest allowing caller to decide when to do the validation:

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?

One other note, you don't seem to have the need of having the same exact method validate() declared in both parent and child classes.

发布评论

评论列表(0)

  1. 暂无评论