Reputation: 1175
I am trying to create a factory class in Typescript. The factory should be set up to create a specific class of object, including default parameters set up at factory initialization.
Here's what I've come up with so far:
type Constructor<T> = new(...args: any) => T;
class Factory<T> {
private params: ConstructorParameters<Constructor<T>>;
private ctor: Constructor<T>;
init<TCtor extends Constructor<T>>(tConstructor: TCtor,
...params: ConstructorParameters<TCtor>)
{
this.ctor = tConstructor;
this.params = params;
}
create(): T {
return new this.ctor(...this.params);
}
}
class ClassWithParams { constructor(a: number) { } }
const factory = new Factory<ClassWithParams>();
//factory.init(ClassWithParams);
// Compilation error - missing param a
factory.init(ClassWithParams, 1);
console.log(factory.create());
// instance of ClassWithParams
The above code works well (Typescript playground). However, it requires an init()
call for the factory directly after construction. I can't move the init()
code into the constructor because init()
relies on a generic parameter TCtor
in order to properly typecheck the parameter list.
I could make TCtor
a generic parameter of the class instead, but that would mean every time Factory is referenced generically an additional type parameter would need to be supplied for no reason.
Any ideas to remove that init()
call?
Upvotes: 0
Views: 1736
Reputation: 31803
What's wrong with the following code
type Constructor<T> = new (...args: any[]) => T;
class Factory<T, C extends Constructor<T> = Constructor<T>> {
params: ConstructorParameters<C>;
ctor: Constructor<T>;
constructor(tConstructor: Constructor<T>,
...params: ConstructorParameters<C>) {
this.ctor = tConstructor;
this.params = params;
}
create(): T {
return new (this.ctor)(...this.params)
}
}
class ClassWithParams { constructor(a: number) { this.a = a; } a: number }
const factory1 = new Factory(ClassWithParams);
const factory2 = new Factory(ClassWithParams, '1');
const factory3 = new Factory(ClassWithParams, 0);
const value = new Factory(ClassWithParams, 0).create().a;
As seen in this playground it's convenient and correct.
Upvotes: 1