1

I'm trying to create a factory that creates instance using a string id.
I will let the code explain itself...

class A
{

}

class B
{

}

 class MyFactory{

     private static _instance: MyFactory;

     private _map: { [id: string]: object; } = {};

     private constructor() {
        // Map the id and classes
        this._map["A"] = A;
        this._map["B"] = B;
     }

     public createInstance(id: string) : object {
         let newInstance = null;
         if (this._map[id] != null) {
             newInstance = Object.create(this._map[id]);
             newInstance.constructor.apply(newInstance);
         }

         return newInstance;
     }

     public static get instance() {
         return this._instance || (this._instance = new this());
     }
}

I'm a bit struggling with what should I save in the map and how should I use it to construct a new instance from that class...

1 Answer 1

3

The original example always gives a Function {} object instance because classes were passed as argument for Object.create instead of the prototype property of those classes:

//original
newInstance = Object.create(this._map[id]);
//updated
newInstance = Object.create(this._map[id].prototype);

This updated version would set the prototype to the correct object but the problem is that you are using object as type, the compiler does not allow access to .prototype property. If you change to any, it will compile but you can't use the constructor to initialize the object:

newInstance.constructor.apply(newInstance);
// If in your map you had ordinary functions this would work
// but because they are classes, they result in the run time error ...
// TypeError: Class constructor A cannot be invoked without 'new' 

A solution would be changing the annotations from object to any and then use the new operator.

newInstance = new this._map[id]();

If some kind of relation was established between the classes then other kind of casts would be applied for a better type check support. Look for the section about interfaces for constructors in the typescript handbook to see if that would fit the the index declaration for the _map.

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

2 Comments

If I use any for the map value, what do I set there? _map[id] = A; ?
Yes. Classes are Functions and Functions are Objects so they can be used as any other kind of value would - this._map["A"] = A; . Using any as type of a value is not the best solution though because it gives no hint for the compiler to check if an operation on that value is valid.

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.