如何将字符串或类传递给方法来创建实例 [英] How to pass a string or class to a method to create instance
问题描述
我将使用以下方法,它通过将类型传递给它来工作,例如 obj.addComponent(MyClass)
。这很好用。
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 type
parameter by adding | string
to it, but it now gives me errors saying:
不能对表达式使用'new' type缺少一个调用或构造签名。
Cannot use 'new' with an expression whose type lacks a call or construct signature.
我是否仍然要修改它以便我可以传递一个类名或者该类的字符串版本?
Is there anyway for me to modify this so that I can pass either a Class name in or a string version of the class?
这是我的不起作用:
public addComponent<T extends Component>(type: ComponentType<T> | string): T {
let comp;
comp = new type() as T;
comp.name = comp.constructor.name;
}
以下是它的依赖关系:
class Component extends Obj {
}
interface ComponentType<T extends Component> {
new(): T;
}
我尝试过使用 Object.create()
,它工作正常,但后来我收到一个新错误:
I have tried using Object.create()
, which works fine, but then I get a new error:
未捕获的TypeError:无法分配给只读属性对象'[对象]'的'名称'
Uncaught TypeError: Cannot assign to read only property 'name' of object '[object Object]'
编辑:
最后我希望能够将以下内容传递给 addComponent
:
In the end I would like to be able to pass the following to addComponent
:
obj.addComponent(MyClass);
或
obj.addComponent("MyClass");
推荐答案
没有办法让类使用名称javascript,它没有类似java ClassLoader
的东西。
您可以通过创建自己的机制来解决这个问题,并且可能有很多方法这样做,但这里有3个选项。
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)维护组件类的注册表:
(1) Maintain a registry for your component classes:
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并从中获取名称。
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.
这里有一个变体,就是使用装饰器: / p>
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 {}
(游乐场代码)
(2)将组件包装在命名空间中(正如@Shilly在评论中建议的那样):
(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<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();
}
(操场上的代码)
如果你采用这种方法,那么你需要确保所有导出组件类。
If you're going with this approach then you need to make sure that all the component classes are exported.
(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
阅读所有关于利弊。
但它仍然是一个选项所以我正在列出它。
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.
这篇关于如何将字符串或类传递给方法来创建实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!