Essentially, the goal is to have the constructor implementation appear as follows:
constructor(params: FooParams) { Object.assign(this, params); }
Here, the `Object.assign()` method is utilized to copy all (own, enumerable) properties from `params` into the newly constructed class instance.
However, the challenge lies in informing the compiler that `Foo` should possess the same properties as `FooParams`. One workaround is to employ declaration merging to specify that `Foo` also extends `FooParams`:
interface Foo extends FooParams { }
class Foo {
constructor(params: FooParams) {
Object.assign(this, params);
}
}
This approach ensures the desired functionality:
const foo = new Foo({ a: "hey", b: Math.PI, c: true });
console.log(foo.a.toUpperCase()) // HEY
console.log(foo.b.toFixed(2)) // 3.14
Nevertheless, this solution isn't entirely type safe; declaration merging somewhat resembles a type assertion since the compiler won't "validate" it. If the `Object.assign()` line is omitted from the constructor, the compiler won't detect it, potentially leading to runtime errors. Therefore, caution is advised.
Link to code Playground