常识表明,对于返回类型,子类型应该是协变的,而对于参数类型,逆变。因此,应该拒绝以下内容,因为E.f
的严格协变参数类型:
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 :(得分:4)
根据krontogiannis'上面的注释,当比较函数类型时,一个可以是另一个的子类型,因为源参数类型可以分配给相应的目标参数类型或,因为相应的目标参数类型可分配给源参数类型。在语言规范中,这称为function parameter bivariance。
允许bivariant参数类型的原因,而不是" naive"期待逆变,是对象是可变的。在纯语言中,逆变是唯一合理的选择,但是对于可变对象,协方差或逆变是否有意义取决于您是否正在阅读或写入结构。由于目前没有办法(目前)在类型系统中表达这种区别,因此双变量是一种合理的(尽管是不健全的)妥协。