我正在使用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
的构造函数的装饰器中引发错误,因为{{ 1}}是happy
。
如何更改装饰器,使其仅在undefined
是this
的实例而不是target
的后代时才运行其验证代码?
答案 0 :(得分:2)
基于帕特里克·罗伯茨(Patrick Roberts)的思想的解决方案,另外提供了防止定义子类和忘记@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;
}
}
}
};
}