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

标签 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) 编译器在这种情况下不能忽略警告是否有任何实际原因?

最佳答案

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

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

关于TypeScript:子类型化和协变参数类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39569016/

相关文章:

javascript - Renderer2 错误 - id 与任何元素都不匹配

javascript - angular2 ngOnChanges 不适用于多个输入

java - 没有继承的子类型和没有子类型的继承?

java - 扩展类的 Scala 特征是如何为 JVM 目标编译的?

java - 我们可以用 Java(或 Kotlin)表示 "self class"吗?

javascript - Angular 6 创建 TemplateRef 的实例

angular - 如何使用 TypeScript 和 Node 正确导入 Firestore?

c# - 如何从接口(interface)返回派生程度更高的类型?

python - 如何在 Python 中获取 n 个数组的 n x n 协方差矩阵?

c# - 为什么 C# 出的泛型类型参数会违反协变?