Skip to content

协变与逆变

TypeScript 中,协变(covariance)逆变(contravariance) 是类型系统处理 子类型关系 时的重要概念。不管是协变还是逆变本质上都是为了类型的安全

协变

  • 子类型可以替换父类型
  • 适用于:函数的返回值,参数赋值
ts
class Animal {}
class Dog extends Animal {}

type Fn1 = () => Dog
type Fn2 = () => Animal

let f1: Fn1 = () => new Dog()
let f2: Fn2

f2 = f1 // ✅ OK,因为 Dog 是 Animal 的子类型

函数返回值为什么是协变?

原来期待的父类型,但是返回的是子类型,子类型具备所有父类型的属性,因此在实际使用子类型时是类型安全的

逆变

  • 父类型可以替换子类型
  • 适用于:函数参数
ts
class Animal {}
class Dog extends Animal {}

type Fn1 = (arg: Animal) => void
type Fn2 = (arg: Dog) => void

let f1: Fn1 = (a: Animal) => {}
let f2: Fn2

f2 = f1 // ✅ OK
// f1 = f2 // ❌ 不行

为什么函数的形参是逆变?

f2系统期望的是类型Dog,但是实际运行的函数是f1,开发者会将类型Dog传入f1,f1期望的类型是Animal。此时类型安全

f1系统期望的是类型Animal,但是实际运行的函数是f2,开发者会将Animal传入f2,f2期望的类型是Dog,此时类型不安全