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

Rol*_*oly 7 covariance subtyping typescript

常识表明,子类型在返回类型方面应该是协变的,但在参数类型方面应该是逆变的.因此,应该拒绝以下内容,因为严格协变的参数类型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))
Run Code Online (Sandbox Code Playgroud)

的确,运行程序打印

Uncaught TypeError: o.g is not a function
Run Code Online (Sandbox Code Playgroud)

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

Rol*_*oly 6

按照krontogiannis '上方评论,比较函数类型时,可以是其他的子类型要么因为一个源参数类型可分配给相应的目标参数类型,或因为与相应的目标参数类型可分配给所述源参数的类型。在语言规范中,这称为函数参数双方差。

与逆变的“天真”期望相反,允许双变量参数类型的原因是对象是可变的。在纯语言中,逆变是唯一合理的选择,但对于可变对象,协变或逆变是否有意义取决于您是读取结构还是写入结构。由于(目前)无法在类型系统中表达这种区别,因此二元性是一种合理(尽管不合理)的折衷方案。