TypeScript:子类型和协变参数类型

时间:2016-09-19 08:51:29

标签: typescript covariance subtyping

常识表明,对于返回类型,子类型应该是协变的,而对于参数类型,逆变。因此,应该拒绝以下内容,因为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)在这种情况下编译器是否可以省略警告是否有任何实际原因?

1 个答案:

答案 0 :(得分:4)

根据krontogiannis'上面的注释,当比较函数类型时,一个可以是另一个的子类型,因为源参数类型可以分配给相应的目标参数类型,因为相应的目标参数类型可分配给源参数类型。在语言规范中,这称为function parameter bivariance

允许bivariant参数类型的原因,而不是" naive"期待逆变,是对象是可变的。在纯语言中,逆变是唯一合理的选择,但是对于可变对象,协方差或逆变是否有意义取决于您是否正在阅读或写入结构。由于目前没有办法(目前)在类型系统中表达这种区别,因此双变量是一种合理的(尽管是不健全的)妥协。