【问题标题】:TypeScript compiler not enforcing type parameter in implementation of generic interface?TypeScript 编译器在实现泛型接口时不强制执行类型参数?
【发布时间】:2016-10-24 19:41:13
【问题描述】:

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

interface IFoo {}

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

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

interface IFooHandler<F extends IFoo> {
    handle(foo: F): string
}

现在,我们来实现IFooHandler接口,具体实现IFoo作为类型参数:

class FooAHandler implements IFooHandler<FooA> {
    handle(foo: FooB): string {
        return "Hello, Foo A!";
    }
}

在 2.0.3 版本中使用 tsc 编译完美。所以这是我的问题:为什么编译?

请注意,我在FooAHandlerhandle() 函数中使用了FooB 作为参数类型。我假设这段代码会触发编译器错误,因为IFooHandler&lt;F&gt; 接口规定handle 方法应该接受F 类型的参数(因此,如果是IFooHandler&lt;FooA&gt;,则类型为FooA -- 并且不是FooB)。

我在 TypeScript 文档中找不到有关此行为的任何信息。这种行为是否是故意的,如果是,其背后的原因是什么?还是我只是以错误的方式使用此功能?


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

FooAHandler.java:1: 错误 FooAHandler 不是抽象的并且没有覆盖 IFooHandler 中的抽象方法句柄(FooA)

【问题讨论】:

标签: generics typescript


【解决方案1】:

发生这种情况是因为编译器不按名称比较类型,而是检查它们的结构,并且由于 IFooFooAFooB 都是空的,所以它们都是相等的。

即使在做的时候:

interface IFoo {
    a: string;
}

class FooA implements IFoo {
    a: string;
}

class FooB implements IFoo {
    a: string;
}

编译器仍然不会抱怨,但是一旦我们区分了FooAFooB

class FooA implements IFoo {
    a: string;
    b: string;
}

class FooB implements IFoo {
    a: string;
    c: string;
}

我们得到编译器错误:

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'.  

(code in playground)

附注:
空对象(就像你的所有接口一样)将始终接受所有内容:

interface IFoo { }

function fn(foo: IFoo) {}

fn(3); // ok
fn("string"); // ok
fn({ key: "value" }); // ok

(code in playground)

【讨论】:

  • +1,很好的答案,谢谢!我实际上可能过度简化了我的示例,因为我的实际界面当然不是全部为空,但这个答案让我走上了正确的轨道。
  • 有没有办法获得最初预期的行为?
  • @Kir “最初预期的行为”是什么?如果您的意思是您希望编译器通过声明的类型而不是结构来比较类型,那么不,这就是 ts 编译器的工作方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-15
  • 2016-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多