TypeScript 中协变、逆变与双变的使用小结

 更新时间:2026年06月09日 09:14:11   作者:csdddn  
在 TypeScript 的类型系统中,协变(Covariance)、逆变(Contravariance)与双变(Bivariance)是三个关键概念,理解这些概念对于编写安全、灵活且可维护的代码至关重要,本文将深入探讨这些概念,并解释它们在 TypeScript 中的应用

在 TypeScript 的类型系统中,协变(Covariance)、逆变(Contravariance)与双变(Bivariance)是三个关键概念,它们描述了类型在继承关系或函数参数传递中的变化行为。理解这些概念对于编写安全、灵活且可维护的代码至关重要。本文将深入探讨这些概念,并解释它们在 TypeScript 中的应用。

协变(Covariance)

协变是指子类型可以替代父类型的位置,同时保持类型安全。在 TypeScript 中,协变最常见于数组和函数返回类型。

数组的协变

考虑以下代码示例:

class Animal {}
class Dog extends Animal {}

let animals: Animal[] = [];
let dogs: Dog[] = [];

animals = dogs; // 允许,因为 Dog[] 是 Animal[] 的子类型

在这个例子中,Dog[]Animal[] 的子类型,因此可以将 dogs 数组赋值给 animals 变量。这种行为是协变的,因为它允许子类型数组替代父类型数组。

函数返回类型的协变

函数返回类型也支持协变。这意味着如果一个函数的返回类型是另一个函数返回类型的子类型,那么前者可以替代后者。

function getAnimal(): Animal {
    return new Animal();
}

function getDog(): Dog {
    return new Dog();
}

let getAnimalFunc: () => Animal = getDog; // 允许,因为 Dog 是 Animal 的子类型

在这个例子中,getDog 函数的返回类型是 Dog,它是 Animal 的子类型。因此,getDog 可以赋值给 getAnimalFunc,因为它的返回类型是协变的。

逆变(Contravariance)

与协变相反,逆变是指父类型可以替代子类型的位置。在 TypeScript 中,逆变主要出现在函数参数类型中。

函数参数类型的逆变

考虑以下代码示例:

function processAnimal(animal: Animal): void {}
function processDog(dog: Dog): void {}

let processFunc: (dog: Dog) => void = processAnimal; // 允许,因为 Animal 是 Dog 的父类型

在这个例子中,processAnimal 函数的参数类型是 Animal,它是 Dog 的父类型。因此,processAnimal 可以赋值给 processFunc,因为它的参数类型是逆变的。这意味着 processAnimal 可以处理 Dog 类型的参数,因为它也可以处理 Animal 类型的所有实例。

双变(Bivariance)

双变是指类型在协变和逆变的情况下都允许替换。在 TypeScript 中,函数参数类型在非严格模式下默认是双变的,但这可能导致类型安全问题。

函数参数类型的双变

考虑以下代码示例:

class Cat extends Animal {}

function processCat(cat: Cat): void {}

let processFunc: (animal: Animal) => void = processCat; // 在非严格模式下允许

在这个例子中,processCat 函数的参数类型是 Cat,它是 Animal 的子类型。在非严格模式下,TypeScript 允许将 processCat 赋值给 processFunc,即使 processFunc 的参数类型是 Animal。这种行为是双变的,因为它既允许协变也允许逆变。然而,这种灵活性可能导致类型安全问题,因为 processFunc 可能被调用时传入一个非 Cat 类型的 Animal 实例。

严格模式下的行为

在严格模式下(启用 strictFunctionTypes 选项),TypeScript 会禁用函数参数类型的双变,只允许逆变。这提高了类型安全性,因为函数参数类型必须与目标类型兼容或为其父类型。

// 启用 strictFunctionTypes 后
let strictProcessFunc: (animal: Animal) => void = processCat; // 错误,不允许双变

实际应用中的考虑

理解协变、逆变和双变对于编写类型安全的代码至关重要。在数组和函数返回类型中,协变允许更灵活的代码复用。在函数参数类型中,逆变提供了更严格的类型检查,防止潜在的类型错误。双变虽然提供了灵活性,但在严格模式下应避免使用,以维护类型安全性。

在实际开发中,应根据具体需求选择合适的类型变化行为。对于数组和函数返回类型,通常可以利用协变来简化代码。对于函数参数类型,在严格模式下应遵循逆变原则,确保类型安全。

结论

TypeScript 中的协变、逆变和双变是类型系统的重要组成部分,它们影响着类型在继承关系和函数参数传递中的行为。协变允许子类型替代父类型,逆变允许父类型替代子类型,而双变则提供了更大的灵活性,但可能牺牲类型安全性。通过理解这些概念,开发者可以编写出更安全、更灵活且更易于维护的 TypeScript 代码。

到此这篇关于TypeScript 中协变、逆变与双变的使用小结的文章就介绍到这了,更多相关TypeScript 协变、逆变与双变内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JavaScript垃圾回收机制原理总结深入探究

    JavaScript垃圾回收机制原理总结深入探究

    就像人类会产生垃圾一样,程序运行过程中也会产生垃圾,如果不及时回收轻则将会拖慢程序运行,重则会导致系统崩溃,也就是所谓的内存泄漏。所以垃圾回收非常必要
    2022-10-10
  • 兼容所有浏览器的js复制插件Zero使用介绍

    兼容所有浏览器的js复制插件Zero使用介绍

    这篇文章主要介绍了兼容所有浏览器的js复制插件Zero的使用,需要的朋友可以参考下
    2014-03-03
  • WEB前端实现裁剪上传图片功能

    WEB前端实现裁剪上传图片功能

    文件上传功能在各大网站经常会用到,今天小编通过本文给大家介绍了WEB前端实现裁剪上传图片功能的相关资料,需要的朋友可以参考下
    2016-10-10
  • Web端选择本地文件的几种方式汇总

    Web端选择本地文件的几种方式汇总

    在开发中经常需要实现本地文件选择功能,无论是上传图片、视频,还是处理批量文件,Web端提供了多种方式来实现这一需求,每种方式都有其独特的优缺点和适用场景,本文将详细总结Web端选择本地文件的几种方式,需要的朋友可以参考下
    2025-04-04
  • JS组件福利大放送 推荐12款好用的Bootstrap组件

    JS组件福利大放送 推荐12款好用的Bootstrap组件

    Bootstrap组件福利大放送,这篇文章主要为大家推荐了几款好用的Bootstrap组件,感兴趣的小伙伴们可以参考一下
    2016-07-07
  • 分析js闭包引起的事件注册问题

    分析js闭包引起的事件注册问题

    这篇文章主要为大家分析了js闭包引起的事件注册问题,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • JS实现公告上线滚动效果

    JS实现公告上线滚动效果

    这篇文章主要为大家详细介绍了JS实现公告上线滚动效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-01-01
  • JavaScript箭头函数与普通函数的具体区别详细解析

    JavaScript箭头函数与普通函数的具体区别详细解析

    箭头函数(Arrow Function)是JavaScript在ES6中引入的一种简化函数定义的语法,下面这篇文章主要介绍了JavaScript箭头函数与普通函数具体区别的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2026-04-04
  • js防止表单重复提交实现代码

    js防止表单重复提交实现代码

    重复提交、重复刷新、防止后退等等都是属于系统为避免重复记录而需要解决的问题,在客户端去处理需要针对每一种的可能提出相应的解决方案,然而在服务器端看来只不过是对于数据真实性的检验问题
    2012-09-09
  • JS实现的简单图片切换功能示例【测试可用】

    JS实现的简单图片切换功能示例【测试可用】

    这篇文章主要介绍了JS实现的简单图片切换功能,结合实例形式分析了javascript结合时间函数定时触发控制图片的遍历与切换操作相关技巧,需要的朋友可以参考下
    2017-02-02

最新评论