Map `ConstructorParameters<T>` tuple to object type

Viewed 372

I wonder if there is any way of mapping ConstructorParameters<T> to an object where each key is the parameter name and the key is the type of the parameter.

What I mean is, given:

class User {
  public id: number;

  constructor(
      public readonly name: string,
      public readonly surname: string,
  ) {}

  get fullname(): string { ... }
  public isAdmin(): boolean { ... }
}

With ConstructorParameters<typeof User> I get the type [name: string, surname: string]. Maybe this can be mapped to the following type { name: string, surname: string }? Note that the type should omit: id, fullname & isAdmin as they are not present on the constructor.

I've seen https://stackoverflow.com/a/49062616 which is a really cool solution but it breaks with getters and public properties that are not present in the constructor.

1 Answers

I don't think so. The "name" of the parameters of a function don't actually have any meaning outside the context of the function. For example, you can do this:

type FuncType = (foo: string) => void;

const MyFunc: FuncType = (bar) => {
  return bar;
}

The "name" of foo and bar don't match at all, but the order and type do, which is all that really matters. Probably similar to how you can destructure an array and give the items arbitrary names; the items in an array don't have names to begin with:

const array = [1, 2, 3];
const [one, two, three] = array;

About the closest you could probably get is to get the order and types of your constructor as an object, but I'm not sure how that would be useful:

type ConstructorParametersIndices<T extends new (...args: any) => any> =
  T extends new (...args: infer P) => any ? {[K in keyof P]: K} : never;

type A = ConstructorParameters<typeof User>;
// [name: string, surname: string]

type B = ConstructorParametersIndices<typeof User>;
// [name: "0", surname: "1"]

type C = {[P in B[number] as P]: A[P]};
/*  {
 *    0: string;
 *    1: string;
/*  }
Related