Dynamically return a class constructor in TypeScript

I am trying to create a mechanism in TypeScript to return a new instance of a class based on a string parameter representing the class name. Basically, I am trying to create a factory, only I cannot figure out how to do it in TypeScript. In pure JS, I could have avoided this by simply storing all class constructors in the key / value object and calling new ClassDictionary[className]();

- this is not the most reliable solution, but it works in this situation. I can't seem to get the right combination of types and castings to accomplish this in TypeScript. Is there a better way? I haven't been able to find examples of factory patterns in TypeScript, so right now I just have an instruction for fast switching, which is ugly and inflexible.

+3


source to share


2 answers


You can add a function declaration for each class in the dictionary, it might look like this: ( http://www.typescriptlang.org/Handbook#declaration-merging-merging-interfaces ):

class MyClass { 
    myMethod() { return "my return"; }
}

function factory(className: "Date"): Date;
function factory(className: "Number"): Number;
function factory(className: "MyClass"): MyClass;
function factory(className: string) { 

    var ClassDictionary = {
        "Date": Date,
        "Number": Number,
        "MyClass": MyClass
    };

    return new ClassDictionary[className]();
}

var d = factory("Date");

/* Its a date. */
alert(d.toISOString());

var n = factory("Number");

/* Now a number. */
alert(n.toPrecision());

var c = factory("MyClass");

/* And now MyClass. */
alert(c.myMethod());

      

Works on the playground ( Example )

Or in another way



// ...
var ClassDictionary = { };

ClassDictionary["Date"] = Date;
function factory(className: "Date"): Date;

ClassDictionary["Number"] = Number;
function factory(className: "Number"): Number;

ClassDictionary["MyClass"] = MyClass;
function factory(className: "MyClass"): MyClass;

function factory(className: string) { 
    return new ClassDictionary[className]();
}
// ...

      

Or with arguments:

class MyClass {
    constructor(public myReturn: string) { }
    myMethod() { return this.myReturn; }
}

var ClassDictionary = { };

ClassDictionary["Date"] = Date;
function factory(className: "Date"): Date;

ClassDictionary["Number"] = Number;
function factory(className: "Number", value?: number): Number;

ClassDictionary["MyClass"] = MyClass;
function factory(className: "MyClass", myReturn: string): MyClass;

function factory(className: string, valueOrMyReturn?: number | string) { 
   if(valueOrMyReturn) return new ClassDictionary[className](valueOrMyReturn);
    return new ClassDictionary[className]();
}

var d = factory("Date");

/* Its a date. */
alert(d.toISOString());

var n = factory("Number", 42);

/* Now a number. */
alert(n.toPrecision());

var c = factory("MyClass", "This is the answer!");

/* And now MyClass. */
alert(c.myMethod());

      

+4


source


Suppose you have a class definition:

module UI
{
    export class MyClass
    {
        constructor( data: any )
        {}
     }
}

      

You can use a construction like this:

public static CreateController(  data: IControllerData ): any
    {
        return new data.namespace[data.controller]( data.initializationData );
    }

      



where data is JS objects and something like this:

var data = {
            namespace: UI,
            controller: "MyClass"// <- this is the class name
            initializationData: {} // this is the parameters that you want to pass in constructor
}

      

to create a new instance of the MyClass class.

+1


source







All Articles