2017-02-25 135 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}()`);