Hi FE !
Ai
git
前端面试题
前端小tip
  • vite
  • webpack
npm
  • vue2
  • vue3
react
GitHub
Ai
git
前端面试题
前端小tip
  • vite
  • webpack
npm
  • vue2
  • vue3
react
GitHub
  • 逆变和协变

逆变和协变

定义

协变:类型推导到其子类型的过程,A | B -> A & B 就是一个协变
逆变:类型推导到其超类型的过程

如何判断函数子类型?

为了方便描述,「Dog => Dog」 表示「参数为 Dog,返回值为 Dog 的函数」
其他类型的子类型我们很好判断,函数的子类型却很难,比如有关系 Animal -> Dog -> Shepherd

Animal => Shepherd 是  Dog => Dog 子类型吗?
是的

我们如果把视角划分,Dog => Dog  作为
参数的传入者:只能保证传入 Dog 参数,所以当我们定义参数为 Animal 时,只能使用 Animal 上的属性和方法,而 Dog 肯定有,就能保证类型的正确。
使用返回值者:保证只使用 Dog 方法,所以当我们定义返回值为 Shepherd,使用者只使用 Dog 上的属性和方法,而 Shepherd 肯定有,就能保证类型的正确。
所以,Dog => Dog  -> Animal => Shepherd
也称 参数是逆变的,返回值是协变的。


至于你为什么这么少看到协变和逆变的概念,只因为 TypeScript 只有一处逆变,就是参数

举例:

协变

Covariance
如果T ≤ U,那么F<T> ≤ F<U>也成立,这就叫协变。很容易理解吧。
这里协变主要讲函数的返回值类型的检查。

type Co<V> = () => V;

// Co<Dog> ≤ Co<Animal>
const animalFn: Co<Animal> = () => {
  return new Animal();
}

const dogFn: Co<Dog> = () => {
  return new Dog();
}

let a: Co<Animal> = dogFn; // ok,dogFn返回Dog,Dog本身就是Animal
let b: Co<Dog> = animalFn; // error,animalFn返回Animal,Animal不一定是Dog,有可能不会doDogThing

可以看到,函数的返回值类型要协变才安全,否则ts可能会报错。

逆变

Cotravariance
跟协变相反,如果T ≤ U,那么F<U> ≤ F<T>成立,这就叫逆变。
这里逆变主要讲的是函数的参数类型的检查。

注意,是函数赋值时对参数的检查,并不是参数赋值时的检查。

当开启了--strictFunctionTypes或者--strict模式,ts才对函数参数类型进行逆变检查。
type Cotra<V> = (input: V) => void;

// Cotra<Animal> ≤ Cotra<Dog>
const animalFn: Cotra<Animal> = (input) => {
  input.doAnimalThing();
}

const dogFn: Cotra<Dog> = (input) => {
  input.doDogThing();
}

let a: Cotra<Animal> = dogFn; // error,Animal没有doDogThing方法
let b: Cotra<Dog> = animalFn; // ok
这里可能有点难理解,但是细想一下,就会发现这是合理的。
方法a我们定义入参为一个Animal,但是赋值是dogFn,调用方法a时如果真的传入Animal,由于Animal没有doDogThing方法,一定会执行出错。所以这里ts会提示错误。
但反过来就没问题。方法b传入Dog,Dog继承Animal,是有doAnimalThing方法的。
Edit this page
最近更新: 2025/6/27 02:24
Contributors: qdleader
qdleader
本站总访问量 129823次 | 本站访客数 12人