dynamic加载打字稿类(打字稿的reflection)
我希望能够实例化一个打字稿类,在那里我得到的类和构造详细信息在运行时。 我想写的函数将采取类名称和构造函数参数。
export function createInstance(moduleName : string, className : string, instanceParameters : string[]) { //return new [moduleName].[className]([instancePameters]); (THIS IS THE BIT I DON'T KNOW HOW TO DO) }
你可以尝试:
var newInstance = Object.create(window[className].prototype); newInstance.constructor.apply(newinstance, instanceparameters); return newInstance;
编辑此版本正在使用TypeScript操场,例如:
class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return "Hello, " + this.greeting; } } //instance creation here var greeter = Object.create(window["Greeter"].prototype); greeter.constructor.apply(greeter, new Array("World")); var button = document.createElement('button'); button.innerText = "Say Hello"; button.onclick = function() { alert(greeter.greet()); } document.body.appendChild(button);
正如你使用TypeScript我假设你想要input加载的对象。 所以这里是示例类(和一个接口,因为您正在select加载其中一个实现,例如)。
interface IExample { test() : string; } class Example { constructor (private a: string, private b: string) { } test() { return this.a + ' ' + this.b; } }
所以你会使用某种加载器来给你一个实现:
class InstanceLoader { constructor(private context: Object) { } getInstance(name: string, ...args: any[]) { var instance = Object.create(this.context[name].prototype); instance.constructor.apply(instance, args); return instance; } }
然后像这样加载它:
var loader = new InstanceLoader(window); var example = <IExample> loader.getInstance('Example', 'A', 'B'); alert(example.test());
目前,我们有一个演员: <IExample>
– 但是当添加generics时,我们可以做到这一点,并使用generics。 它会看起来像这样(记住它不是语言的一部分!)
class InstanceLoader<T> { constructor(private context: Object) { } getInstance(name: string, ...args: any[]) : T { var instance = Object.create(this.context[name].prototype); instance.constructor.apply(instance, args); return <T> instance; } } var loader = new InstanceLoader<IExample>(window); var example = loader.getInstance('Example', 'A', 'B');
如果你有一个特定的命名空间/模块,对于你想创build的所有类,你可以简单地这样做:
var newClass: any = new MyNamespace[classNameString](parametersIfAny);
更新:没有命名空间使用new window[classname]()
在TypeScript中,如果你在一个名称空间之外声明了一个类,它会为“类函数”生成一个variables。 这意味着它被存储在当前的作用域(最有可能的window
除非你在另一个作用域下运行它,比如nodejs)。 这意味着你可以做一个new window[classNameString]
:
这是一个工作的例子(所有的代码,没有命名空间):
class TestClass { public DoIt() { alert("Hello"); } } var test = new window["TestClass"](); test.DoIt();
为了看到它的工作原理,生成的JS代码如下所示:
var TestClass = (function () { function TestClass() { } TestClass.prototype.DoIt = function () { alert("Hello"); }; return TestClass; }()); var test = new window["TestClass"](); test.DoIt();
这在使用ES6模块的TypeScript 1.8中起作用:
import * as handlers from './handler'; function createInstance(className: string, ...args: any[]) { return new (<any>handlers)[className](...args); }
类在handler
模块中导出。 它们可以从其他模块重新导出。
export myClass {}; export classA from './a'; export classB from './b';
至于在模块中传递模块名称,我不能使它工作,因为ES6模块不能dynamic加载。
打字稿0.9.1 ,你可以做这样的操场 :
class Handler { msgs:string[]; constructor(msgs:string[]) { this.msgs = msgs; } greet() { this.msgs.forEach(x=>alert(x)); } } function createHandler(handler: typeof Handler, params: string[]) { var obj = new handler(params); return obj; } var h = createHandler(Handler, ['hi', 'bye']); h.greet();