2016-09-19 59 views
6

常识意味着子类型应该与返回类型协变,但相对于参数类型相反。因此,下面应该被拒绝,因为严格的协变参数类型的E.f的:TypeScript:子类型和协变参数类型

interface C { 
    f (o: C): void 
} 

interface D extends C { 
    g(): void // give D an extra service 
} 

class E implements C { 
    // implement f with a version which makes stronger assumptions 
    f (o: D): void { 
     o.g() // rely on the extra service promised by D 
    } 
} 

// E doesn't provide the service required, but E.f will accept 
// an E argument as long as I invoke it via C. 
var c: C = new E() 
console.log('Try this: ' + c.f(c)) 

事实上,运行程序打印

Uncaught TypeError: o.g is not a function 

所以:(1)有什么理由在这里(想必是一个,但不满意和JavaScripty); (2)在这种情况下,为什么编译器不能省略警告,是否有任何实际原因?

+0

我认为这将成为打字稿github页面的一个很好的问题。 :) – toskv

+0

检查此Typescript [函数二进制](https://github.com/Microsoft/TypeScript/issues/1394)此问题。 – krontogiannis

+1

我认为“bivariance”(通过< or >相关)总比没有打字好,但它仍然非常危险。 Iinvariance会更安全,但我认为它与从JS继承的其他需求交互不佳。谢谢,这确实有用和相关。 – Roly

回答

1

作为每krontogiannis“高于评论,比较函数类型时,一个可以是其它的一个亚型,因为一个源参数类型可分配给相应的目标参数类型,,因为相应的目标参数类型可分配给源参数类型。在语言规范中,这称为function parameter bivariance

允许双变量类型的原因与“天真”期望的相反性相反,是因为对象是可变的。在纯粹的语言中,逆变是唯一的理智选择,但是对于可变对象而言,无论协变还是逆变都有意义,取决于您是从结构读取还是写入结构。由于在类型系统中没有办法(现在)来表达这种区别,所以双变量是合理的(尽管不合理)妥协。

+0

另请参阅[对语言的最近更改](https://github.com/Microsoft/TypeScript/pull/15104)。 – Roly