如何让我的类装饰器只在继承链中的最外层类上运行?
Posted
技术标签:
【中文标题】如何让我的类装饰器只在继承链中的最外层类上运行?【英文标题】:How can I make my class decorator only run on the outermost class in an inheritance chain? 【发布时间】:2019-03-28 05:39:40 【问题描述】:我正在使用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
被实例化时,当super
在Child
的构造函数/装饰器中被调用时,验证器将在Parent
的构造函数装饰器中抛出错误,因为happy
是undefined
。
如何更改我的装饰器,使其仅在this
是target
的实例而不是target
的后代时才运行其验证代码?
【问题讨论】:
if (this.constructor === target)
?
@PatrickRoberts 我认为你很接近,但 this.constructor
将是包装类,永远不会等于 target
,因此装饰器需要保存包装类,以便可以比较 this.constructor
给它。想写一个更正后的答案吗?
【参考方案1】:
基于 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;
;
【讨论】:
在我看来,使用if (Object.getPrototypeOf(<any>this.constructor) === target)
不会那么麻烦,这样您就不会用实现细节污染类的静态属性。
@PatrickRoberts 这种方式不提供对没有@autoValidate
的子类的保护。如果不需要这种保护,当然可以。如果是这样,自然会使用符号。我不相信拥有一个以字符串命名的静态属性有什么大不了的,但是使用符号很容易,所以我更新了答案。
在将类序列化为 JSON 时使用符号很好地避免成员被拾取。以上是关于如何让我的类装饰器只在继承链中的最外层类上运行?的主要内容,如果未能解决你的问题,请参考以下文章