简体   繁体   English

TypeScript中方差、协方差、逆变和双方差的区别

[英]Difference between Variance, Covariance, Contravariance and Bivariance in TypeScript

Could you please explain using small and simple TypeScript examples what is Variance, Covariance, Contravariance and Bivariance?您能否使用小而简单的 TypeScript 示例解释什么是方差、协方差、逆变和双方差?

[CONTINUOUS UPDATE] [持续更新]

Useful links:有用的链接:

  1. Another one good answer of Oleg Valter related to the topic Oleg Valter另一个与该主题相关的好答案

  2. Very good explanation of*-riance by Titian-Cernicova-Dragomir Titian-Cernicova-Dragomir对*-riance 的很好解释

  3. Stephan Boyer blog 斯蒂芬博耶博客

  4. Scala documentation - good explanation with examples Scala 文档- 用例子很好的解释

  5. @Titian's answer 1 @Titian的回答1

  6. @Titian's answer 2 @Titian的回答2

  7. Vlad Riscutia 's blog弗拉德·里斯库蒂亚的博客

  8. Mark Seemann 's article马克·西曼的文章

  9. @jcalz explanation @jcalz 解释

Variance has to do with how a generic type F<T> varies with respect to its type parameter T .方差与泛型类型F<T>相对于其类型参数T变化有关。 If you know that T extends U , then variance will tell you whether you can conclude that F<T> extends F<U> , conclude that F<U> extends F<T> , or neither, or both.如果您知道T extends U ,那么方差会告诉您是否可以得出结论F<T> extends F<U> ,得出结论F<U> extends F<T> ,或者两者都没有,或两者兼而有之。


Covariance means that F<T> and T co - vary .协方差意味着F<T>T That is, F<T> varies with (in the same direction as) T .也就是说, F<T>T变化(在相同的方向上)。 In other words, if T extends U , then F<T> extends F<U> .换句话说,如果T extends U ,那么F<T> extends F<U> Example:例子:

  • Function or method types co-vary with their return types: Function 或方法类型与其返回类型共同变化:

     type Co<V> = () => V; function covariance<U, T extends U>(t: T, u: U, coT: Co<T>, coU: Co<U>) { u = t; // okay t = u; // error; coU = coT; // okay coT = coU; // error! }

Other (un-illustrated for now) examples are:其他(暂时未说明)示例是:

  • objects are covariant in their property types, even though this not sound for mutable properties对象的属性类型是协变的,即使这对于可变属性来说听起来并不好
  • class constructors are covariant in their instance types class 构造函数的实例类型是协变的

Contravariance means that F<T> and T contra - vary .逆变意味着F<T>T反向变化 That is, F<T> varies counter to (in the opposite direction from) T .也就是说, F<T>T逆向变化(在相反的方向上)。 In other words, if T extends U , then F<U> extends F<T> .换句话说,如果T extends U ,那么F<U> extends F<T> Example:例子:

  • Function types contra-vary with their parameter types (with --strictFunctionTypes enabled): Function 类型与其参数类型相反(启用--strictFunctionTypes ):

     type Contra<V> = (v: V) => void; function contravariance<U, T extends U>(t: T, u: U, contraT: Contra<T>, contraU: Contra<U>) { u = t; // okay t = u; // error; contraU = contraT; // error! contraT = contraU; // okay }

Other (un-illustrated for now) examples are:其他(暂时未说明)示例是:

  • objects are contravariant in their key types对象的键类型是逆变的
  • class constructors are contravariant in their construct parameter types class 构造函数的构造参数类型是逆变的

Invariance means that F<T> neither varies with nor against T : F<T> is neither covariant nor contravariant in T .不变性意味着F<T>既不随 T 变化也不反对TF<T>T中既不协变也不逆变。 This is actually what happens in the most general case.这实际上是最一般情况下发生的情况。 Covariance and contravariance are "fragile" in that when you combine covariant and contravariant type functions, its easy to produce invariant results.协变和逆变是“脆弱的”,因为当你结合协变和逆变类型函数时,它很容易产生不变的结果。 Example:例子:

  • Function types that return the same type as their parameter neither co-vary nor contra-vary in that type: Function 类型返回与其参数相同的类型,在该类型中既不协变也不反变:

     type In<V> = (v: V) => V; function invariance<U, T extends U>(t: T, u: U, inT: In<T>, inU: In<U>) { u = t; // okay t = u; // error; inU = inT; // error! inT = inU; // error! }

Bivariance means that F<T> varies both with and against T : F<T> is both covariant nor contravariant in T .双变量意味着F<T>随 TT变化: F<T>T既是协变的也不是逆变的。 In a sound type system, this essentially never happens for any non-trivial type function.在健全的类型系统中,这对于任何非平凡类型 function 基本上都不会发生 You can demonstrate that only a constant type function like type F<T> = string is truly bivariant (quick sketch: T extends unknown is true for all T , so F<T> extends F<unknown> and F<unknown> extends T , and in a sound type system if A extends B and B extends B , then A is the same as B . So if F<T> = F<unknown> for all T , then F<T> is constant).您可以证明只有常量类型 function 像type F<T> = string是真正的双变量(快速草图: T extends unknown对所有T都是正确的,所以F<T> extends F<unknown>F<unknown> extends T ,并且在健全的类型系统中,如果A extends B并且B extends B ,则AB相同。因此,如果所有TF<T> = F<unknown> ,则F<T>是常数)。

But Typescript does not have nor does it intend to have a fully sound type system.但是 Typescript 没有也不打算拥有完全健全的类型系统。 And there is one notable case where TypeScript treats a type function as bivariant:还有一个值得注意的情况是 TypeScript 将类型 function 视为双变量:

  • Method types both co-vary and contra-vary with their parameter types (this also happens with all function types with --strictFunctionTypes disabled):方法类型与它们的参数类型共同变化和反向变化(这也发生在所有 function 类型禁用--strictFunctionTypes ):

     type Bi<V> = { foo(v: V): void }; function bivariance<U, T extends U>(t: T, u: U, biT: Bi<T>, biU: Bi<U>) { u = t; // okay t = u; // error; biU = biT; // okay biT = biU; // okay }

Playground link to code Playground 代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM