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.
source to share
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());
source to share
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.
source to share