1

I would like to infer the types of a constructor of a class and map them to an Object. I can use ConstructorParameters, but this gives me a Tuple which I would need to transform to an Object. Here is what I'm trying to do:

type ToObject<T> = ???

export class ValueObject {
  constructor(readonly username: string, readonly password: string) {}

  static create(value: ToObject<ConstructorParameters<typeof ValueObject>>): ValueObject {
    return new ValueObject(value.username, value.password)
  }
}

ValueObject.create({ a: 'foo', b: 'bar' })  // KO
ValueObject.create(['foo', 'bar']) // KO
ValueObject.create({ username: 'foo', password: 1 }) // KO
ValueObject.create({ username: 'foo', password: 'bar' }) // OK

How could I achieve this?

César Alberca
  • 2,321
  • 2
  • 20
  • 32
  • Related: https://stackoverflow.com/a/54599556/157247 I've pinged Titian since I couldn't modify his solution there to fit your use case. I'm not 100% sure you can get the name from a named tuple, but there may be another way to get the type for `value` that you need. – T.J. Crowder Feb 04 '21 at 12:06
  • I mean, if `username` and `password` are the only data properties `ValueObject` has, you *could* just use `ValueObject` itself. Remember that TypeScript types are *structural*, not *nominative*. If you used `ValueObject` as the type of `value` in `create`, the only thing that would matter to TypeScript is that `value` has the public data properties that `ValueObject` has. But it feels misleading to just say `create(value: ValueObject): ValueObject`... – T.J. Crowder Feb 04 '21 at 12:07
  • 1
    @T.J.Crowder I don't think this conversion can be done at the type level. You need runtime code, since a tuple has an order an is indexed while an object values don't have an order and are named. The labels in tuples are (AFAIK) only a documentation feature, not something you can concretely resolve. And while object property order is guaranteed, TS won't enforce it, somebody could just pass `{password, username}`. So, I don't think a free conversion between the two types is possible. – VLAZ Feb 04 '21 at 12:11
  • 1
    There is [an interesting FR for TS](https://github.com/microsoft/TypeScript/issues/5326) which will allow destructuring a parameter into object properties. It seems it's not done yet but if it *is*, you'd be able to do `constructor({readonly username, readonly passwor})` which can greatly simplify construction via object argument. – VLAZ Feb 04 '21 at 12:14
  • 1
    @T.J.Crowder This is not possible. While tuples now do preserve names they are not accessible from the type system. – Titian Cernicova-Dragomir Feb 04 '21 at 12:17
  • Thanks for you comments @T.J.Crowder, it seems indeed that it can't be done at the moment. It would have been pretty neat in order to create value objects. – César Alberca Feb 04 '21 at 13:02
  • @VLAZ yeah, that PR seems to be the same thing I want to achieve. – César Alberca Feb 04 '21 at 13:03
  • 1
    Thanks @TitianCernicova-Dragomir! That would explain why I was singularly unsuccessful at it. :-) (As opposed to the many other times I've been singularly unsuccessful doing something in TypeScript that was *entirely* possible. :-) ) – T.J. Crowder Feb 04 '21 at 14:20

0 Answers0