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.