TypeScript编译器在通用接口的实现中不强制执行类型参数?

时间:2016-10-24 19:41:13

标签: generics typescript

考虑具有两个实现的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完美编译。所以这是我的问题:为什么 这个编译?

请注意,我在FooB的{​​{1}}函数中使用了FooAHandler作为参数类型。我假设此代码会触发编译器错误,因为handle()接口规定IFooHandler<F>方法应接受handle类型的参数(因此,如果{{1}类型F - 和IFooHandler<FooA> )。

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

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

  

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

1 个答案:

答案 0 :(得分:4)

这是因为编译器没有按名称比较类型,它会检查它们的结构,因为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