没有办法在javascript中使用名称来获取类,它没有类似于java的东西ClassLoader
.
您可以通过创建自己的机制来解决这个问题,并且可能有很多方法可以做到这一点,但这里有 3 个选项。
(1) 维护组件类的注册表:
const REGISTRY: { [name: string]: ComponentType<Component> } = {};
class Component {}
class MyComponent1 extends Component {}
REGISTRY["MyComponent1"] = MyComponent1;
class MyComponent2 extends Component {}
REGISTRY["MyComponent2"] = MyComponent2;
type ComponentType<T extends Component> = {
new(): T;
}
function factory<T extends Component>(type: ComponentType<T> | string): T {
return typeof type === "string" ?
new REGISTRY[type]() as T:
new type();
}
(操场上的代码)
如果您采用这种方法,那么我建议REGISTRY
一个保存集合的对象,这样您就可以只添加 ctor 并从中获取名称。
有一个变体,那就是使用装饰器:
function register(constructor: typeof Component) {
REGISTRY[(constructor as any).name] = constructor;
}
@register
class MyComponent1 extends Component {}
@register
class MyComponent2 extends Component {}
(操场上的代码)
(2) 将组件包装在命名空间中(正如 @Shilly 在评论中建议的那样):
namespace components {
export class Component {}
export class MyComponent1 extends Component {}
export class MyComponent2 extends Component {}
export type ComponentType<T extends Component> = {
new(): T;
}
export function forName(name: string): ComponentType<Component> {
if (this[name] && this[name].prototype instanceof Component) {
return this[name];
}
}
}
function factory<T extends components.Component>(type: components.ComponentType<T> | string): T {
return typeof type === "string" ?
new (components.forName(type))() as T:
new type();
}
(操场上的代码)
如果您采用这种方法,那么您需要确保导出所有组件类。
(3)使用eval
class Component {}
class MyComponent1 extends Component {}
class MyComponent2 extends Component {}
type ComponentType<T extends Component> = {
new(): T;
}
function factory<T extends Component>(type: ComponentType<T> | string): T {
return typeof type === "string" ?
new (eval(type))() as T:
new type();
}
(操场上的代码)
这不是推荐的方法,您可以阅读所有关于缺点的信息在使用eval
在很多地方。
但这仍然是一个选择,所以我将其列出。