'Create extra boolean property with name suffix `_ro`
Can I create an extra property with a property decorator?
The way I'm trying to do this obviously does not work.
const RoProp = () => {
return <T>(target: T, memberName: keyof T) => {
const roPropName = `${String(memberName)}_ro`;
let roPropVal = false;
Object.defineProperty(target, roPropName, {
set(v: boolean) {
roPropVal = v;
},
get(): boolean {
return roPropVal;
},
enumerable: true,
});
};
};
class ExampleClass {
@RoProp() testProp: string;
// Property 'testProp_ro' does not exist on type 'ExampleClass'.(2339)
constructor({ testProp, testProp_ro }: ExampleClass) {
this.testProp = testProp;
this.testProp_ro = testProp_ro; // Property 'testProp_ro' does not exist on type 'ExampleClass'.(2339)
}
}
const exampleInst = new ExampleClass({
testProp: "a test",
testProp_ro: false, // Argument of type '{ testProp: string; testProp_ro: boolean; }' is not assignable to parameter of type 'ExampleClass'. Object literal may only specify known properties, and 'testProp_ro' does not exist in type 'ExampleClass'.(2345)
});
exampleInst.testProp_ro = true; // Property 'testProp_ro' does not exist on type 'ExampleClass'.(2339)
Playground Link: Trying to create property with decorator
How can this be done, if at all?
Solution 1:[1]
If I could extend my class with a utility type?
It is easy to add properties to types, the main issues is that classes still need to declare the properties to not cause errors.
E.g. when extending it via implements:
type Roify<T extends object> = T & {
[K in keyof T as `${Exclude<K, symbol>}_ro`]: boolean;
}
interface IExampleClass {
testProp: string;
}
class ExampleClass implements Roify<IExampleClass> {
@RoProp() testProp: string;
// Still needs to be declared
testProp_ro: boolean;
constructor({ testProp, testProp_ro }: Roify<IExampleClass>) {
this.testProp = testProp;
this.testProp_ro = testProp_ro;
}
}
When trying to use a base class the issue comes from lack of initialization, so to fix that you could make the property abstract, but then you have to declare even the origin property again:
abstract class ExampleClassCore {
// Error without `abstract`
@RoProp() abstract testProp: string;
}
class ExampleClass extends ExampleClassCore
implements Roify<ExampleClassCore> {
// Still needs to be declared
testProp: string;
testProp_ro: boolean;
constructor({ testProp, testProp_ro }: Roify<ExampleClassCore>) {
super();
this.testProp = testProp;
this.testProp_ro = testProp_ro;
}
}
I also tried to use mix-in classes but that resulted in even more of a mess and numerous errors.
Maybe there is some type wizardry that I have overlooked or do not know about, though.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | H.B. |
