gpt4 book ai didi

javascript - 用于实例验证的 ES/TS 装饰器

转载 作者:行者123 更新时间:2023-11-30 20:57:28 25 4
gpt4 key购买 nike

我想使用装饰器来验证我的实例:

 function min(minVal) {
return (target, key) => {
let value = target[key];

const getter = () => value;
const setter = (val) => {
if (val < minVal) {
throw new Error(`Value smaller than ${minVal}`);
}
value = val;
}
Reflect.deleteProperty[key];
Reflect.defineProperty(target, key, {
get: getter,
set: setter
});
}
}

function max, String, Number ...

class User {

@String
name: String

@Number
@max(100)
@min(0)
age: Number

static validate(obj) {
???
}
}

这在我直接使用实例时有效,但我希望能够调用验证方法并传入一个普通对象:

User.validate({ name: 'Jon', age: 23}) // ok
User.validate({ name: 'Jon', age: -5}) // error

有没有办法在不创建 User 实例的情况下将装饰器应用于传递的对象?

最佳答案

首先,您对支持字段的实现存在问题。因为您使用局部变量 value ,它存在于一个函数中,该函数为使用装饰器的类+属性调用一次,所有实例将共享一个属性的相同支持字段,例如以下代码将无法按预期工作:

class User {
@min(0)
age: Number
}

var u = new User();
u.age = 1;
var u2 = new User();
u2.age = 2;

console.log(u.age); // outputs 2 instead of 1
console.log(u2.age); // outputs 2

要在对象文字上运行验证,您可以保留所有验证器的静态列表,并在调用时将装饰器添加到该静态列表中。其实现可能如下所示(代码还解决了我上面提到的问题):

function validation(validator) : PropertyDecorator & MethodDecorator{
return (target, key: PropertyKey, propDesc?: PropertyDescriptor) => {
let privateKey = "_" + key.toString();
propDesc = propDesc || {
configurable: true,
enumerable: true,
};
propDesc.get = propDesc.get || (function () { return this[privateKey] });

const originalSetter = propDesc.set || (function (val) { this[privateKey] = val });
propDesc.set = function (val) {
validator(val);
originalSetter.call(this, val);
}

const validators: Array<(target: object) => void> = target.constructor['validators'] || (target.constructor['validators'] = []);
validators.push((target) => {
validator(target[key]);
})

return propDesc;
}
}
function min(minVal) {
return validation((val) => {
if (val < minVal) {
throw new Error(`Value smaller than ${minVal}`);
}
});
}

function max(maxValue) {
return validation((val) => {
if (val > maxValue) {
throw new Error(`Value greater than ${maxValue}`);
}
});
}

class User {
static validators: Array<(target: object) => void> = [];
static validate(obj: Partial<User>) {
User.validators.forEach(fn => fn(obj));
}
@min(0) @max(100)
age: number

private _ageField : number;
@min(0) @max(100)
get ageProp(): number {
return this._ageField;
}
set ageProp(value: number) {
this._ageField = value;
}

}
User.validate({
age: 10,
ageProp: 10
});

var u = new User();
u.age = 10;
u.ageProp = 10;

编辑:更新答案以处理属性而不仅仅是字段。

关于javascript - 用于实例验证的 ES/TS 装饰器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47505484/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com