Generics TypeScript编译器在泛型接口的实现中没有强制类型参数?

Generics TypeScript编译器在泛型接口的实现中没有强制类型参数?,generics,typescript,Generics,Typescript,考虑一个带有两种实现的TypeScript接口: interface IFoo {} class FooA implements IFoo {} class FooB implements IFoo {} 接下来,考虑一个通用接口,它接受IFoo作为类型参数的实现: interface IFooHandler<F extends IFoo> { handle(foo: F): string } class FooAHandler implements IFooHandl

考虑一个带有两种实现的TypeScript接口:

interface IFoo {}

class FooA implements IFoo {}
class FooB implements IFoo {}

接下来,考虑一个通用接口,它接受IFoo作为类型参数的实现:

interface IFooHandler<F extends IFoo> {
    handle(foo: F): string
}
class FooAHandler implements IFooHandler<FooA> {
    handle(foo: FooB): string {
        return "Hello, Foo A!";
    }
}
使用版本2.0.3中的tsc,这可以完美地编译。所以我的问题是:为什么要编译

注意,我在FooAHandler的handle函数中使用了FooB作为参数类型。我假设这段代码会触发一个编译器错误,因为IFooHandler接口规定handle方法应该接受类型为F的参数,因此,对于IFooHandler,类型为FooA-而不是FooB

我在TypeScript文档中找不到任何关于这种行为的信息。这种行为是故意的吗?如果是,背后的原因是什么?还是我只是用错了这个功能

为了进行比较,在Java中实现完全相同的示例时省略了代码,因为它非常类似,会产生预期的编译错误:

java:1:error FooAHandler不是抽象的,并且不重写IFooHandler中的抽象方法handleFooA


这是因为编译器不按名称比较类型,而是检查它们的结构,并且由于IFoo、FooA和FooB都是空的,所以它们都相等

即使在这样做时:

interface IFoo {
    a: string;
}

class FooA implements IFoo {
    a: string;
}

class FooB implements IFoo {
    a: string;
}
编译器仍然不会抱怨,但一旦我们区分了FooA和FooB:

我们得到编译器错误:

Class 'FooAHandler' incorrectly implements interface 'IFooHandler<FooA>'.  
  Types of property 'handle' are incompatible.  
    Type '(foo: FooB) => string' is not assignable to type '(foo: FooA) => string'.  
      Types of parameters 'foo' and 'foo' are incompatible.  
        Type 'FooA' is not assignable to type 'FooB'.  
          Property 'c' is missing in type 'FooA'.  

之所以发生这种情况,是因为编译器没有按名称比较类型,而是检查它们的结构,而且由于IFoo、FooA和FooB都是空的,所以它们都相等

即使在这样做时:

interface IFoo {
    a: string;
}

class FooA implements IFoo {
    a: string;
}

class FooB implements IFoo {
    a: string;
}
编译器仍然不会抱怨,但一旦我们区分了FooA和FooB:

我们得到编译器错误:

Class 'FooAHandler' incorrectly implements interface 'IFooHandler<FooA>'.  
  Types of property 'handle' are incompatible.  
    Type '(foo: FooB) => string' is not assignable to type '(foo: FooA) => string'.  
      Types of parameters 'foo' and 'foo' are incompatible.  
        Type 'FooA' is not assignable to type 'FooB'.  
          Property 'c' is missing in type 'FooA'.  

这在常见问题解答中讨论了好几次,并且基本上是@RyanCavanaugh的副本,谢谢链接。哎哟,我真不敢相信我错过了FAQ中的第一个问题。无论如何,这种行为现在对我来说更有意义了!谢谢你的评论。这在FAQ中讨论了好几次,而且基本上是@RyanCavanaugh的副本,谢谢你的链接。哎哟,我真不敢相信我错过了FAQ中的第一个问题。无论如何,这种行为现在对我来说更有意义了!谢谢你的评论。+1,回答得很好,谢谢!我可能实际上过于简化了我的示例,因为我的实际界面当然不全是空的,但这个答案让我走上了正确的轨道。有没有办法获得最初预期的行为?@Kir最初预期的行为是什么?如果您的意思是希望编译器通过声明的类型而不是结构来比较类型,那么不,这就是ts编译器的工作方式。+1,很好的答案,谢谢!我可能实际上过于简化了我的示例,因为我的实际界面当然不全是空的,但这个答案让我走上了正确的轨道。有没有办法获得最初预期的行为?@Kir最初预期的行为是什么?如果您的意思是希望编译器通过声明的类型而不是结构来比较类型,那么不,这就是ts编译器的工作方式。