[英]TypeScript doesn't seem to check types on a class instance property
[英]Can typescript property decorators modify instance members instead of the entire class?
我想写一个消毒剂装饰器,我可以把它放在所有用户输入的字符串字段上。 这只是将标准的.set(newValue)
替换为.set( sanitize(newValue) )
。 但是我发现下面的代码只适用于一个实例。 相同 class 的第二个实例最终共享 currentValue。 进一步阅读后,这实际上是预期的,但我无法弄清楚如何针对每个实例进行操作。
import "reflect-metadata";
export const Sanitize = () => {
return (target: any, propertyKey: string | symbol) => {
let currentValue: any = sanitiseString(options, `${target[propertyKey] || ''}`);
Reflect.deleteProperty(target, propertyKey);
Reflect.defineProperty(target, propertyKey, {
get: () => currentValue,
set: (newValue: string) => {
currentValue = sanitiseString(newValue);
},
});
}
}
编辑 1:最小可重现示例:
import "reflect-metadata";
const sanitiseString = (valToSanitise: string) => {
// do some stuff, return clean value
return valToSanitise;
}
const Sanitize = () => {
return (target: any, propertyKey: string | symbol) => {
let currentValue: any = sanitiseString(`${target[propertyKey] || ''}`);
Reflect.deleteProperty(target, propertyKey);
Reflect.defineProperty(target, propertyKey, {
get: () => currentValue,
set: (newValue: string) => {
currentValue = sanitiseString(newValue);
},
});
}
}
class UserInput {
constructor(propOne: string, propTwo: string, propThree: number) {
this.propOne = propOne;
this.propTwo = propTwo;
this.propThree = propThree;
}
@Sanitize() propOne: string
@Sanitize() propTwo: string
propThree: number
}
const inputOne = new UserInput('input 1, prop 1', 'input 1, prop 2', 1)
const inputTwo = new UserInput('input 2, prop 1', 'input 2, prop 2', 2)
console.log(inputOne)
console.log(inputTwo)
// expected output:
// [LOG]: UserInput: {
// "propOne": "input 1, prop 1",
// "propTwo": "input 1, prop 2",
// "propThree": 1
// }
// [LOG]: UserInput: {
// "propOne": "input 2, prop 1",
// "propTwo": "input 2, prop 2",
// "propThree": 2
// }
//
// actual output:
//
// [LOG]: UserInput: {
// "propThree": 1
// }
// [LOG]: UserInput: {
// "propThree": 2
// }
// When you remove @Sanitize() the fields appear in console.log. When you add @Sanitize() the fields disappear.
// Further, forcing console.log(inputOne.propOne) returns [LOG]: "input 2, prop 1"
// indicating that the property is being written for the class proto and not per instance
console.log(inputOne.propOne)
这里的主要问题是Sanitize()
在每个修饰的 class 属性声明中被调用一次,因此对于任何给定的 class 属性,只有一个currentValue
。 这意味着 class 的两个实例将共享相同的currentValue
。 如果你想为每个class 实例的每个修饰的 class 属性存储一个值,那么你需要访问 class 个实例,并且你必须将值存储在这些实例中(通过不会干扰任何其他实例的属性键) properties),或者在一些 map 中,其键是那些实例。 在下文中,我将展示如何将值存储在 class 实例中,并且为了避免担心属性名称冲突,我将使用symbol
function 的Symbol
output ,保证唯一。
另请注意,将class 原型作为target
参数传递给Sanitize()
,因此您对target
执行的任何操作都会影响原型,而不是 class 的任何实例。当您编写target[propertyKey]
时,您正在查找属性class 原型和string
值属性几乎肯定不会在原型中设置。 所以这可能没有必要或没有用,我们应该摆脱它。
因此,如果您只能直接访问 class 原型,您如何对 class 实例执行任何操作? 那么,为此,您应该使用传递给defineProperty()
的访问器属性描述符的get
方法和set
方法的this
上下文。 这意味着get
和set
需要是methods或至少function
expressions ,而不是arrow function expressions没有不同的this
上下文。
好的,足够的解释,这是代码:
const Sanitize = () => {
return (target: any, propertyKey: string | symbol) => {
const privatePropKey = Symbol();
Reflect.defineProperty(target, propertyKey, {
get(this: any) {
return this[privatePropKey]
},
set(this: any, newValue: string) {
this[privatePropKey] = sanitiseString(newValue);
},
});
}
}
让我们确保它按您的预期工作。 让sanitiseString
实际上做一些事情:
const sanitiseString = (valToSanitise: string) => {
return valToSanitise+"!";
}
现在我们的 class:
class UserInput {
constructor(propOne: string, propTwo: string, propThree: number) {
this.propOne = propOne;
this.propTwo = propTwo;
this.propThree = propThree;
}
@Sanitize() propOne: string
@Sanitize() propTwo: string
propThree: number
}
最后让我们看看它是否有效:
const inputOne = new UserInput('input 1, prop 1', 'input 1, prop 2', 1)
const inputTwo = new UserInput('input 2, prop 1', 'input 2, prop 2', 2)
console.log(inputOne.propOne, inputOne.propTwo, inputOne.propThree)
console.log(inputTwo.propOne, inputTwo.propTwo, inputTwo.propThree);
// GOOD OUTPUT
// [LOG]: "input 1, prop 1!", "input 1, prop 2!", 1
// [LOG]: "input 2, prop 1!", "input 2, prop 2!", 2
看起来挺好的。 UserInput
的每个实例都有自己经过净化的propOne
和propTwo
属性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.