TypeScript编译器在通用接口的实现中不强制实施类型参数? [英] TypeScript compiler not enforcing type parameter in implementation of generic interface?

查看:184
本文介绍了TypeScript编译器在通用接口的实现中不强制实施类型参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 接口IFoo {} 

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

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

 接口IFooHandler< F extends的IFoo> {
handle(foo:F):string
}

现在,让我们使用 IFoo 的特定实现作为类型参数来实现 IFooHandler 接口:

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




$ b

这个编译完美,使用 tsc 2.0.3版本。所以这里是我的问题:为什么不会这个编译?

请注意,我已经使用 FooB 作为 FooAHandler handle()函数中的参数类型。因为 IFooHandler< F> 接口规定句柄方法,所以我认为这段代码会触发编译器错误应该接受 F 类型的参数(如果是 IFooHandler< FooA> ,则类型为 FooA - 和不是 FooB )。

在TypeScript文档中找不到这种行为。这种行为是否有意为之,如果是这样,那背后的理由是什么?或者我只是用错误的方式使用这个功能?






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


FooAHandler.java:1:错误FooAHandler不是抽象的,在IFooHandler中不重写抽象方法句柄(FooA)


解决方案

发生这种情况是因为编译器不会不按名称比较类型,它检查它们的结构,并且自 IFoo FooA

即使在这样做:




pre> interface IFoo {
a:string;
}

class FooA实现IFoo {
a:string;
}

class FooB实现IFoo {
a:string;
}

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

  class FooA实现IFoo {
a:string;
b:string;
}

class FooB实现IFoo {
a:string;
c:string;
}

我们得到编译器错误:

 类'FooAHandler'错误地实现了接口'IFooHandler< FooA>'。 
属性'句柄'的类型不兼容。
键入'(foo:FooB)=>字符串'不可分配给类型'(foo:FooA)=>串'。
参数'foo'和'foo'的类型不兼容。
类型'FooA'不可分配为键入'FooB'。
'FooA'类型中缺少属性'c'。

游乐场代码

附注:

空对象(就像所有的接口一样)会一直接受:

 接口IFoo {} 

函数fn(foo:IFoo){}

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

游乐场代码

Consider a TypeScript interface with two implementations:

interface IFoo {}

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

Next, consider a generic interface that accepts an implementation of IFoo as type parameter:

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

Now, let's implement the IFooHandler interface with a specific implementation of IFoo as a type parameter:

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

This compiles perfectly, using tsc in version 2.0.3. So here's my question: Why does this compile?

Note that I've used FooB as parameter type in the FooAHandler's handle() function. I would assume that this code would trigger a compiler error, as the IFooHandler<F> interface prescribes that the handle method should accept a parameter of type F (so, in case of a IFooHandler<FooA>, of type FooA -- and not FooB).

I could not find anything on this behaviour in the TypeScript documentation. Is this behaviour intentional, and if so, what's the reasoning behind it? Or am I just using this feature the wrong way?


Just for comparison, implementing the exact same example in Java (omitting the code, as it's quite similar) yields the (expected) compile error:

FooAHandler.java:1: error FooAHandler is not abstract and does not override abstract method handle(FooA) in IFooHandler

解决方案

This happens because the compiler doesn't compare the types by name, it checks their structures, and since IFoo, FooA and FooB are all empty then they are all equal.

Even when doing:

interface IFoo {
    a: string;
}

class FooA implements IFoo {
    a: string;
}

class FooB implements IFoo {
    a: string;
}

The compiler still won't complain, but once we differentiate between FooA and FooB:

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

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

We get the compiler error:

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)

A side note:
Empty objects (like all of your interfaces) will always accepts everything:

interface IFoo { }

function fn(foo: IFoo) {}

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

(code in playground)

这篇关于TypeScript编译器在通用接口的实现中不强制实施类型参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆