I'm trying to build a mechanism in TypeScript to return a new instance of a class based on a string parameter representing the name of the class. Basically, I'm trying to create a factory, only I can't quite figure out how to do this in TypeScript. In pure JS, I could get away with this by just storing all the class constructors in a key/value object and calling new ClassDictionary[className]();
- it's not the most robust solution, but it works in this situation. I can't seem to get the right combination of types and casting to accomplish this in TypeScript. Is there a better way? I haven't been able to find any examples of factory pattern in TypeScript, so right now I've just got a bit switch statement, which is ugly and inflexible.
The constructors of class can have types of their own. Above syntax, generic types are used, indicating that the constructor will return an object that can be a class instance of type T. Using the typed constructor, one can implement the factory design pattern in TypeScript.
The constructor is now explicitly defined - unlike the ES5 way which we had to assume / work out was in fact a constructor. One major difference is that in TypeScript we need to declare the class properties and their respective types upfront - typically you’d place these at the top of the class.
Therefore any valid JavaScript is also valid TypeScript. Let’s take a look at a simple Pizza constructor function, this is the ES5 way of creating a class and constructor, the function acting as our constructor: We pass the name argument through our constructor, and can simply type it as string.
Parameter Properties. TypeScript offers special syntax for turning a constructor parameter into a class property with the same name and value. These are called parameter properties and are created by prefixing a constructor argument with one of the visibility modifiers public, private, protected, or readonly.
You can add a function declaration for every class in the dictionary, this can looks like this (Visit: https://www.typescriptlang.org/docs/handbook/declaration-merging.html):
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 in the Playground (Sample)
Or in a other 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());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With