2017-02-25 131 views
2

我一直在寻找到与JavaScript中的字符串创建类,直到我碰到这个传来:从打字稿/ Angular2类字符串创建实例

var instance = new window[classString](); 

然而,这似乎并没有在打字稿工作,因为有缺少类型信息。

详情:

interface SomeInterface{ 
    structuredData: any; 
} 

class A implements SomeInterface { 

} 

我在数据库中存储JSON序列类信息。比方说,我有一个模型类A,该类的属性在前端序列化为JSON字符串,并与表示此数据的类名称一起发送到数据库,即数据库包含一个包含该类名称的class_type列。在这种情况下,这将是字符串'A'。现在,我想将这些数据重新存入我的应用程序,并从这些数据中动态构建一个实例。

如果我们看一下JavaScript的实例代码上面我发现,我很乐意做这样的事情:

let instance = new window['A'](); 
instance.structuredData = foo; 

由于这些类包含坚持某个接口的通用参数,我将能够分配序列化数据到那些新实​​例化的实例。

我正在使用Angular2/Webpack,并且非常感谢任何有关如何执行此操作的提示。

当使用代码就像我上面提到的,我得到以下编译器错误:

Cannot use 'new' with an expression whose type lacks a call or construct signature.

如果我尝试使用

declare var window; 

我收到以下错误规避严格的类型检查:

window['classString'] is not a constructor

+0

你用TypeScript代码得到了什么错误? –

+0

@MichaelLiu添加错误消息。 –

+0

我无法重现错误。如果我把'let instance = new window ['A']();'放在一个独立的.ts文件中,它编译得很好。 –

回答

2

由于Angular2巧妙抽象的WebPack的参与,我不千牛确切地说,模块如何加载和详细处理。然而,我的猜测(正如评论中所提到的)是,该类在窗口/全局空间中不可用,因此我提出了一个可能是正确的解决方案(尝试了它并运行,但不确定这是否正确方式做这种类型的事情):

// first I require the module that is named in snake case with a .ts 
// suffix based on the string that is stored in the database 
// so if the stored string is SomeThing, we require the file 
// called 'some_thing.ts'. Note: using lodash to generate that string 
const dynModule = require('./' + _.snakeCase(classTypeString)); 

// next, we get the constructor by the class name from that module 
// which is exactly the string that we stored in the db 
const klass = dynModule[classTypeString]; 

// now we have the constructor function of the class and can 
// instantiate a new class from that 
let instance: SomeInterface = new klass(); 

instance.structuredData = foo; 
+0

问题中的错误特定于Typescript和输入问题。 – estus

0

你可以把这些类的窗口对象里面自己,即使你是其他类中:

(window as any).example = class {}; // replace with you class 
// and then later in code.... 
const classNameStr = 'example'; 
const init = new window[classNameStr](); 

如果你不喜欢写入窗口对象内部,您可以将它们存储在代码中某处的对象/字典中。 或者简单地使用Eval(虽然它不是一个好习惯):

eval(`new ${className}()`);