Reputation: 10949
I have a Typescript application where there is a lot of code like this:
class Model {
prop1: string;
prop2: string;
prop3: string;
constructor(input: ModelInput) {
this.prop1 = input.prop1;
this.prop2 = input.prop1;
this.prop3 = input.prop1;
}
}
type ModelInput = {
prop1: string,
prop2: string,
prop3: string,
}
I'd like to remove some of the boilerplate, specifically by replacing the constructor assignments with:
Object.assign(this, input);
This guarantees that the input fields are set on the constructed instance. However, Typescript doesn't seem to recognize the effect of this. It complains:
Property 'prop{1,2,3}' has no initializer and is not definitely assigned in the constructor.
Is there any way around this problem, or am I stuck repeating every property name in the constructor?
Upvotes: 1
Views: 659
Reputation: 329608
To suppress the error, you could use definite assignment assertions:
class ModelAssert {
prop1!: string;
prop2!: string;
prop3!: string;
constructor(input: ModelInput) {
Object.assign(this, input);
}
}
class ModelDeclare {
declare prop1: string;
declare prop2: string;
declare prop3: string;
constructor(input: ModelInput) {
Object.assign(this, input);
}
}
depending on how you want those properties to be emitted to JavaScript. This is less work than manually copying everything, but still requires a declaration in your class for each property in the input. Also note that if you actually forget to initialize properties, these techniques suppress the error (remove the Object.assign()
line and you still get no warnings).
If you really don't want to make a declaration at all, you can a class factory function implemented with some type assertions like this
function AssignCtor<T extends object>() {
return class {
constructor(t: T) {
Object.assign(this, t)
}
} as { new(t: T): T }
}
and then use it to make constructors of the form "take a parameter of type T
and return a value of type T
". So Model
could be:
class Model extends AssignCtor<ModelInput>() {
method() {
console.log(this.prop1 + ", " + this.prop2 + ", " + this.prop3);
}
}
And you can verify that it works:
const model = new Model({ prop1: "hi", prop2: "okay", prop3: "bye" });
model.method(); // hi, okay, bye
Upvotes: 5