2

TypeScript has convenient "parameter property" shorthand for class constructors so that I don't have to explicitly define every property, like this:

class Pizza {
  constructor(
    private sauce: string,
    private cheese: string,
    public radius: number
  ) {}
}

However, I can also use a constructor that takes an object rather than an argument list (essentially, keyword arguments):

const pizza = new Pizza({sauce: 'marinara', cheese: 'Venezuelan Beaver', radius: 8})

This syntax has a number of conveniences, not least of which is the ability to use the spread operator to easily copy objects:

const anotherPizza = new Pizza({...pizza, radius: 10})

But unfortunately it means I can't use the constructor shortcut to avoid all the boilerplate (I think):

class Pizza {

  private sauce: string;
  private cheese: string;
  private radius: number;

  constructor({sauce, cheese, radius}: {
      sauce: string,
      cheese: string,
      radius: number
  }) {
    this.sauce = sauce;
    this.cheese = cheese;
    this.radius = radius;
  }
}

Is there some way to use an object-literal constructor like this and still avoid assigning every property explicitly?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Sasgorilla
  • 2,403
  • 2
  • 29
  • 56
  • No. The closest you could get is spreading an _array_ (or _tuple_, type-wise) of values. – jonrsharpe Aug 19 '22 at 13:59
  • @jonrsharpe Could you show a brief example of that? I'm still not sure how I can use the parameter property syntax with an array argument. – Sasgorilla Aug 22 '22 at 16:07
  • It wouldn't change the class definition or parameter property syntax _at all_, the point is you'd spread an array e.g. `['marinara', 'Venezuelan Beaver', 8]` to it, instead of an object. – jonrsharpe Aug 22 '22 at 16:08

1 Answers1

1

The closest thing to what you're looking for is to get a tuple of constructor arguments using the relevant utility type. You can then create an array of parameter arguments and spread them (type-safely) to the constructor:

class Pizza {
  constructor(
    private sauce: string,
    private cheese: string,
    public radius: number
  ) {}
}

type PizzaSpec = ConstructorParameters<typeof Pizza>;

const spec: PizzaSpec = ["marinara", "Venezuelan Beaver", 8];

const pizza = new Pizza(...spec);

Playground

Although you can't use an object with property keys, the type you get is a labeled tuple, equivalent to writing:

const spec: [sauce: string, cheese: string, radius: number] = ...;

so you do get a little more documentation than just [string, string, number].

Copying is much more limited, though; dealing with array slices in a type-safe way is pretty complicated.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437