Reputation: 9258
I want to make a Constructor
type that takes a class as a type parameter and returns the signature of its constructor.
This would be useful in defining a static property make
method on a class that can create an instance of that class rather than creating it with a new ClassInstance(...)
statement.
This is what I've got so far:
type ClassConstructorArgs<T> = T extends { new (...args: infer A): any }
? A
: never;
type Constructor<T> = (...args: ClassConstructorArgs<T>) => T;
class Person {
constructor(public name: string, public age: number) {}
static make: Constructor<typeof Person> = (...args) => new Person(...args);
// ^^^^^^^^^^^^^^^^^^^
// Type 'Person' is missing the following properties from type 'typeof Person': prototype, make
}
The problem is that the static make
has an error: Type 'Person' is missing the following properties from type 'typeof Person': prototype, make
I understand that this is because my Constructor
type is wrong, constructors of class T
don't return the class T
itself but an instance of T
.
But then I don't know how I can express that Constructor
returns an instance of T
rather than the class T
itself. Is that even possible in TypeScript?
Upvotes: 3
Views: 196
Reputation: 38046
Typescript has builtin utilities both for ConstructorParameters and InstanceType:
type Constructor<T extends new (...args: any) => any> =
(...args: ConstructorParameters<T>) => InstanceType<T>;
class Person {
constructor(public name: string, public age: number) {}
static make: Constructor<typeof Person> = (...args) => new Person(...args);
}
const p = Person.make('some name', 1); // p is of type Person
If you wonder how these utilities are defined and what's wrong with your attempt, here you go:
type ConstructorParameters<T extends new (...args: any) => any> =
T extends new (...args: infer P) => any ? P : never;
type InstanceType<T extends new (...args: any) => any> =
T extends new (...args: any) => infer R ? R : any;
Upvotes: 2