Нельзя использовать валидировать внутри конструктора родительского класса с классом-валидатором
Я хочу использовать 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')
Результат:
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' } } ]
Когда я вызываю конструктор Dog, код запускает super(), а затем this.validate() класса Animal. Этот метод проверяет экземпляр Dog, и поскольку у Animal нет атрибута breed, код выдает ошибку выше.
Я не знаю, как решить эту проблему и, возможно, поставить проверку внутри конструкторов не очень хорошая идея.
Есть ли обходной путь или лучший способ сделать это?
1 ответ
Причина, по которой вы получаете ошибку, не в том, что 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
}
}
И с тех пор 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?
Еще одно замечание: вам, похоже, не нужен тот же точный метод validate()
объявлены как в родительских, так и в дочерних классах.