I am to use the following method, it works by passing a type to it such as obj.addComponent(MyClass). This works just fine.
I tried to modify the typ
There's no way to get the class using a name in javascript, it doesn't have something similar to the java ClassLoader.
You can get around that by creating your own mechanism, and there are probably many ways to do so, but here are 3 options.
(1) Maintain a registry for your component classes:
const REGISTRY: { [name: string]: ComponentType } = {};
class Component {}
class MyComponent1 extends Component {}
REGISTRY["MyComponent1"] = MyComponent1;
class MyComponent2 extends Component {}
REGISTRY["MyComponent2"] = MyComponent2;
type ComponentType = {
new(): T;
}
function factory(type: ComponentType | string): T {
return typeof type === "string" ?
new REGISTRY[type]() as T:
new type();
}
(code in playground)
If you go with this approach then I suggest to make the REGISTRY an object that holds the collection, that way you can add the ctor only and get the name from that.
There's a variant for this and that's to use a decorator:
function register(constructor: typeof Component) {
REGISTRY[(constructor as any).name] = constructor;
}
@register
class MyComponent1 extends Component {}
@register
class MyComponent2 extends Component {}
(code in playground)
(2) Wrap the components in a namespace (As @Shilly suggested in a comment):
namespace components {
export class Component {}
export class MyComponent1 extends Component {}
export class MyComponent2 extends Component {}
export type ComponentType = {
new(): T;
}
export function forName(name: string): ComponentType {
if (this[name] && this[name].prototype instanceof Component) {
return this[name];
}
}
}
function factory(type: components.ComponentType | string): T {
return typeof type === "string" ?
new (components.forName(type))() as T:
new type();
}
(code in playground)
If you're going with this approach then you need to make sure that all the component classes are exported.
(3) Use eval
class Component {}
class MyComponent1 extends Component {}
class MyComponent2 extends Component {}
type ComponentType = {
new(): T;
}
function factory(type: ComponentType | string): T {
return typeof type === "string" ?
new (eval(type))() as T:
new type();
}
(code in playground)
This isn't a recommended approach, and you can read all about the cons in using eval in a lot of places.
But it's still an option so I'm listing it.