0

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?

4
  • I realized my answer had a mistake in it that caused type information to be lost. Please see the updated version Commented Jun 24, 2019 at 6:58
  • Oh interesting, it seemed to work for me - what type information was lost? Commented Jun 24, 2019 at 7:16
  • The return type of Factory.prototype.create was wrong. Try the new version Commented Jun 24, 2019 at 9:00
  • @AluanHaddad the new implementation is incorrect - there is no type error for incorrect parameters. Did you mean tConstructor: C instead of tConstructor: Constructor<T> ? Commented Jun 25, 2019 at 4:46

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.