7

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

4

1 回答 1

6

根据上面krontogiannis的评论,在比较函数类型时,一个可以是另一个的子类型,因为源参数类型可分配给相应的目标参数类型,或者因为相应的目标参数类型可分配给源参数类型。在语言规范中,这称为函数参数双变量

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

于 2016-12-19T19:20:52.940 回答