2017-03-11 50 views
3

给定两个接口与冲突的成员类型:交集类型为什么可能包含冲突类型?

interface A { x: number } 
interface B { x: string } 

这是不可能的,以限定延伸两者的接口:

interface I extends A, B 
// error TS2320: Interface 'I' cannot simultaneously extend types 'A' and 'B'. 
// Named property 'x' of types 'A' and 'B' are not identical. 

可能定义包括A和交叉路口型B

let c = A & B 
type C = A & B 
// no type errors 

尽管它是不可能创建此类型的实例:

let withNumber: C = { x: 10 } 
error TS2322: Type '{ x: number; }' is not assignable to type 'A & B'. 
Type '{ x: number; }' is not assignable to type 'B'. 
Types of property 'x' are incompatible. 
Type 'number' is not assignable to type 'string'. 

let withString: C = { x: "foo" } 
// The same type error, with `number` and `string` reversed 

是否有技术原因,他们被定义在那个路口的类型不报告冲突?

+1

可以定义该接口:'interface I extends A,B {x:number&string}'! –

回答

3

type操作数can be type parameters; interface... extends操作数必须是具体类型。

这种区别使typeinterface更灵活(这几乎是type的动机)。

其中一个结果是,运营商无法提前知道其全套成员类型,因此无法检测到像本例这样的冲突。

To quote Anders Hejlsberg

现在,对于操作数为类型参数的能力也深深地 影响操作者的(可能的)语义。特别是,运营商必须始终如一地为任意两个具有未知的成员集的操作数工作,因为在类型实例化期间(即,当真实类型被 类型参数替代时)不可能有意义地报告错误 。这引起了& 之间的区别和扩展。因为实际类型总是以扩展名来知道,所以我们 可以做更多的检查并禁止我们认为从经典的OOP角度来看错误的构造。例如,当属性 具有相同名称但不同类型与扩展冲突时,我们可能会出错,而我们 将它们的类型与&合并(即相交)。

欲了解更多信息,请参阅Github issue with a similar questionpull request for intersection types

+0

很好的答案和+1引用安德斯。然而,这已经改变了,你现在可以扩展/实现任意类型别名,即使它们包含映射类型。这是为了支持mixin模式而添加的。请考虑更新您的答案。请参阅https://github.com/Microsoft/TypeScript/wiki/Roadmap#22-february-2017 –

+1

@AluanHaddad据我所知,这个问题的关键点是您可以使用'type T = X&Y' ,但不能'interface I 扩展X,Y {}'。接口可以在2.2中扩展更多类型,但不能使用类型参数。 – joews

+0

好点,这取决于你如何阅读它。我没有把它解释为关于类型参数。这现在是有效的,但需要中间相交'type A = {x:number}; type B = {x:string}; type AB = A & B; interface I extends AB {} declare const i:I; i.x.toExponential(); i.x.trim();'无论如何,这是一个很好的答案。 –