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

标签 typescript covariance variance contravariance invariance

您能否使用小而简单的 TypeScript 示例来解释什么是方差、协方差、逆变和双方差?
[持续更新]
有用链接:

  • Another Oleg Valter 的一个好答案与主题相关
  • Very good explanation of*-rianance 来自 Titian-Cernicova-Dragomir
  • Stephan Boyer博客
  • Scala documentation - 用例子很好的解释
  • @提香的 answer 1
  • @提香的 answer 2
  • Vlad Riscutia 's blog
  • Mark Seemann 's文章
  • 最佳答案

    方差 与泛型类型的方式有关 F<T>因类型参数而异 T .如果你知道 T extends U ,那么方差将告诉您是否可以得出 F<T> extends F<U> 的结论, 得出结论 F<U> extends F<T> ,或两者都不是,或两者兼而有之。

    协方差 意味着 F<T>T共变。即,F<T>随(同方向)T 而变化.换句话说,如果 T extends U ,然后 F<T> extends F<U> .例子:

  • 函数或方法类型随它们的返回类型而变化:
    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!
    }
    

  • 其他(暂时未说明)示例是:
  • 对象在它们的属性类型上是协变的,即使这对于可变属性来说并不合理
  • 类构造函数的实例类型是协变的

  • 逆变意味着 F<T>T相反。即,F<T>T相反(相反方向)变化.换句话说,如果 T extends U ,然后 F<U> extends F<T> .例子:
  • 函数类型与其参数类型相反(启用 --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
    }
    

  • 其他(暂时未说明)示例是:
  • 对象的键类型是逆变的
  • 类构造函数的构造参数类型是逆变的

  • 不变性 意味着 F<T>既不与也不反对 T :F<T>T 中既不协变也不逆变.这实际上是最一般情况下发生的情况。协变和逆变是“脆弱的”,因为当您组合协变和逆变类型函数时,很容易产生不变的结果。例子:
  • 返回与其参数相同类型的函数类型在该类型中既不共变也不反变:
    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!
    }
    

  • 双方差意味着 F<T>随和反对 T :F<T>T 中既是协变又是逆变.在健全的类型系统中,对于任何非平凡的类型函数,这基本上不会发生。您可以证明只有像 type F<T> = string 这样的常量类型函数是真正的双变(快速草图: T extends unknown 对所有 T 都是如此,所以 F<T> extends F<unknown>F<unknown> extends T ,并且在声音类型系统中,如果 A extends BB extends B 6 是相同的 | 6 A 。所以如果 B = F<T> 对于所有 F<unknown> ,那么 T 是常数)。
    但是 Typescript 没有 nor does it intend to have一个完全健全的类型系统。还有one notable case其中 TypeScript 将类型函数视为双变量:
  • 方法类型与其参数类型共变和反变(这也发生在所有禁用 F<T> 的函数类型中):
    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

    关于typescript - TypeScript 中的方差、协方差、逆变和协方差的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66410115/

    相关文章:

    typescript - 什么是 fp-ts 谓词?

    angular - 有没有一种干净的方法可以在 TypeScript 中创建静态可继承的泛型构造函数?

    javascript - Angular 2。 Angular 日历事件单元详细信息模板

    r - R 中的 NearZeroVar 是什么?

    reactjs - React/Typescript 属性 'ID' 在类型 'never' 上不存在 .ts(2339)

    c# - 反方差的常见编程用途是什么?

    c# - IDictionary<K, IEnumerable/IList/ICollection<V>> 上的单一扩展方法

    python - 计算 torch 张量的协方差(2d 特征图)

    postgresql - 检查 postgresql 中时态数据库的最小可变性

    python - 使用 scikit-learn PCA 找到具有最高方差的维度