I'm looking to create a class that will have unknown properties. Basically, I pass an object to its constructor and it uses the properties of that object. This is easy in JavaScript but seemingly a pain in TypeScript.
I'm looking to add several methods to specific objects, not all - or shorthand something like the following (just an example):
function toString() {
return JSON.stringify(this).replace(
/[\u007f-\uffff]/g,
(character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`,
);
}
const obj = { pencil: '✎' };
Object.definePropery(
obj,
'toString',
{ value: toString.bind(obj) }
);
console.log(`${obj}`); // {"pencil":"\u270e"}
This is just an example, but how would I create a class that could simply (just an example):
class MyClass {
constructor(/*...*/) {
// ...
}
toString() {
return JSON.stringify(this).replace(
/[\u007f-\uffff]/g,
(character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`,
);
}
anotherMethod() {
// ...
}
yetAnotherOne() {
// ...
}
}
const myClass1 = new MyClass({ hello: 'world' });
console.log(myClass1.hello); // world
console.log(`JSON: ${myClass1}`); // {"hello":"world"}
console.log(myClass1.anotherMethod());
const myClass2 = new MyClass({ foo: 'bar' });
console.log(myClass2.foo); // bar
console.log(myClass2.yetAnotherOne());
Maybe I'm overcomplicating things, but any help is appreciated.
Thanks!
CodePudding user response:
Anything you can do in JS you can also do in TS, so this is possible. It does, however, go completely against everything TypeScript is meant to be good for, so it's a little annoying to write. You'll just have to cast any MyClass
object to a type with the appropriate fields whenever you want to access them. Most conveniently, any
. Otherwise, you'll have to go through unknown
first:
class MyClass {
constructor(obj: any) {
for (const prop in obj) {
(this as any)[prop] = obj[prop];
}
}
toString() {
return JSON.stringify(this).replace(
/[\u007f-\uffff]/g,
(character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`,
);
}
anotherMethod() {
// ...
}
yetAnotherOne() {
// ...
}
}
const myClass1 = new MyClass({ hello: 'world' });
// casting to any:
console.log((myClass1 as any).hello); // world
console.log(`JSON: ${myClass1}`); // {"hello":"world"}
console.log(myClass1.anotherMethod());
const myClass2 = new MyClass({ foo: 'bar' });
// casting to { foo: string } via unknown:
console.log((myClass2 as unknown as { foo: string }).foo); // bar
console.log(myClass2.yetAnotherOne());
I fail to see why you'd want to do this, but there you go.
CodePudding user response:
From what I gather you would be better just using objects and adding properties as you normally would:
const obj = {pencil: '✎'}
if(condition) obj['lock'] =