2017-04-08 59 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'的确是我的意图,并且准确地描述了我的意思:一个返回类型的新函数。 –

相关问题