1

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?

1 Answer 1

5

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);
  }

}

or declare property modifers:

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

Playground link to code

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.