2017-04-08 21 views
1

爲什麼不編譯?類型不能分配到通用類型

interface ITest { ... }  

class Test implements ITest { ... } 

class Factory<T extends ITest> { 
    constructor(private _Test: typeof Test) { } 

    create(): T { 
     return new this._Test(); 
    } 
} 

它給出Type 'Test' is not assignable to type 'T'. (property) Factory<T extends ITest>._Test: new() => Test

我怎麼可能使它工作是要麼

create(): ITest 

或通過

private _Test: any 

雙方不會真的進行通信(代碼明智)什麼我之後。任何方式,我可以使它的工作?

+0

你怎麼想這個工作?你打算如何使用工廠?你能提供一些示例代碼嗎? –

+0

嗨@SergeyYarotskiy,爲什麼我認爲這將工作,我在我對Rico Kahler的評論中描述。我錯誤地認爲可以使用'typeof CertainClass'來描述實現'ICertainClass'的'CertainClass'的類型。它在沒有涉及泛型的其他類中起作用,但是當我開始在我的Factory上定義泛型時,它指出了對我的類型系統的誤解。 –

回答

4

爲什麼不編譯?

它不編譯,因爲_Test的類型是typeof Test。這可能會造成混淆,所以讓我嘗試打破下來:


打字稿添加「類型」爲JavaScript的世界給你一個方法,說:「我希望這個對象都提供給這些屬性和操作他們。」。在本質上,這是一個type system呢。

打字稿具有typeof運算符,它的作用就像一個type query作爲一種方法上的類型註釋(在:)的右側使用時,從實例化的對象獲得「類型」 typeof爲您提供了一種方式來表示「該對象具有的任何屬性和操作,我想捕獲這些屬性並重用它們來檢查另一個對象的類型」。

以下是使用此typeof運算符的示例。

let myObject = { 
    a: 'a string', 
    b: 5, 
    c: false 
}; 

// notice that the `typeof` operator is on the right of the `:` 
function takesATypeOfMyObject(obj: typeof myObject) { 
    // highlight over `a`, `b`, or `c` to see their type 
    obj.a // (property) a: string 
    obj.b // (property) b: number 
    obj.c // (property) c: boolean 
} 

myObject是一個正常的JavaScript對象字面量。函數takesATypeOfMyObject是一個參數obj的函數,其類型註釋爲typeof myObject。這個函數表示可以接受任何與對象myObject具有相同屬性的對象。

這不會與javascript的typeof運算符相混淆,該運算符只返回一個字符串。 Typescript的typeof運算符是它的類型系統的一部分。請記住,當打字稿編譯爲javascript時,類型和類型註釋將消失。


另一個重要的事情要明白的是班打字稿是如何工作的。類是一把雙刃劍。在打字稿中,類可以同時作爲以下兩種形式使用:

  • 一個類型 - 就像您可以在對象上執行的屬性和操作的定義一樣。除了
  • 構造 - 如在混凝土function你可以用new調用來獲取上述類型

這可能是很有誘惑力的使用類型標註typeof MyClass但是這是最有可能不是你想要的。

考慮下面的例子:

// define a class Animal 
// this creates the type definition of `Animal` as well as 
// the constructor to create an `Animal` 
class Animal { 
    makeNosie() { return 'grrr'; } 
} 

// use the constructor to create an object of type `Animal` 
let myAnimal = new Animal(); 
// now `myAnimal` has an inferred type of `Animal` 

// declare an object to of type `Animal` but instead of using 
// the `Animal` constructor, just define an object literal that 
// conforms to the type of Animal 
let dog: Animal = { 
    makeNosie:() => 'woof' 
}; 
// the type of dog has been declared explicitly and typescript 
// just checks to see if it conforms to the type 

所以希望你看,如果你想一個對象,以符合一個類創建的類型,你不使用typeof運營商,你剛纔說「動物「,而不是typeof Animal

但是,這給我們帶來了一個問題:如果你做了什麼呢?

記住typeof運營商試圖捕捉到被重用的類型。由於class ES同時定義類型和new能函數來創建該類型的對象,什麼typeof Animal實際上做的是查詢動物的構造函數的類型。


好了,現在我們可以在你的代碼終於挖明白爲什麼它不編譯。以下是原始代碼,您粘貼:

interface ITest { }  

class Test implements ITest { } 

class Factory<T extends ITest> { 
    constructor(private _Test: typeof Test) { } 

    create(): T { 
     return new this._Test(); 
    } 
} 

看看的Factoryconstructor。什麼你這段代碼的意思是,「我Factory類的constructor需要符合測試的構造函數的對象。這是一個相當複雜的類型(很可能並非您的本意)。

相反試試這個代碼:

interface ITest { }  

class Test implements ITest { } 

class Factory<T extends ITest> { 
    constructor(private _Test: new() => T) { } 

    create(): T { 
     return new this._Test(); 
    } 
} 

_Test的類型描述已更改爲new() => T這是在說,「工廠的構造函數中返回一個類型T任何new能功能」

希望ŧ帽子是你的意圖。

我希望我已經解決了你你的問題的幫助,以及你表演打字稿是多麼強大。 Typescript正在嘗試做一個非常雄心勃勃和瘋狂的事情:爲所有可能的javascript添加完整類型。我認爲他們做得很好。

+0

謝謝您的廣泛答覆!我在使用TS時有很多的快樂,但仍然在學習,而不是完全精通。你的解決方案確實解決了我的問題爲什麼我感到困惑的是,在我用'typeof Test'注入了非實例化類的情況下,它的工作,但是這不在泛型範圍內(因此'create'只是鍵入以返回ITest')。所以這就隱藏了你對我的誤解,你指出了。我將不得不使用您提供的信息來查看這些案例。再次感謝! –

+0

我不能編輯我的評論了,但'new(...)=> T'的確是我的意圖,並且準確地描述了我的意思:一個返回類型的新函數。 –

相關問題