Ts中逆变和协变—例子生动看完即懂

简介: Ts中逆变和协变—例子生动看完即懂

在了解Ts的逆变和协变之前,我们先了解一下什么叫做鸭子类型


鸭子类型



如果一只鸟走路像鸭子 ,游泳也像,做什么都像,那么这只鸟就可以成为鸭子类型。

我们不用关心鸭子的定义是什么,只要符合我们通常意义上的认知,那么他就是这个物体。

在 TypeScript中,只要对象符合定义的类型约束,那么我们就可以视为他是。


协变



协变,又可以称为鸭子类型


interface A {
    name:string
    age:number
}
interface B {
    name:string
    age:number
    sex:string
}
let a:A = {
    name:"老墨我想吃鱼了",
    age:33,
}
let b:B = {
    name:"老墨我不想吃鱼",
    age:33,
    sex:"女"
}
a = b


接口A中有name和age属性,接口B有name,age和sex属性。 当我们将b赋值给a的时候,因为B类型是A类型的子集,所以我们可以将B赋值给A


回到我们的鸭子类型上,我们可以将A理解成那个鸭子,B理解成那只鸟。因为B中的name像A,B中的age像A,即B满足A的所有特性,所以B就是A类型,可以正确赋值。换句大白话讲,就是B类型只能多,不能少,才可以正确赋值。


我们再从集合的角度来理解协变。刚刚我们提到B是A的子集,相信一定会有同学出来反驳,明明,B的属性比A多,A才是B的子集!


这里的集合概念和我们平时认知的不太一样。大家可以换个角度想,接口中的属性可以相当于我们的限制条件。就拿我们找工作举例子,熟悉React的应聘者是一个集合A,当我们增加我们的招聘要求时,不仅熟悉React,还要熟悉node,满足这两个招聘条件的应聘者又构成一个集合B。那么集合B是不是集合A的子集呢?


相信大家对协变已经有自己的理解了吧!


逆变



逆变一般发生于函数的参数上面


interface A {
    name:string
    age:number
}
interface B {
    name:string
    age:number
    sex:string
}
let a:A = {
    name:"老墨我想吃鱼了",
    age:33,
}
let b:B = {
    name:"老墨我不想吃鱼",
    age:33,
    sex:"女"
}
a = b
let fna = (params:A) => {
}
let fnb = (params:B) => {
}
fna = fnb //错误
fnb = fna //正确


我们刚刚说到B是A的子集, 但是我们在函数的参数中使用A/B类型,为什么和刚刚的结果不一样呢? 只能将fna赋值给fnb


小栗子又来了

我们在使用函数进行赋值的时候,fnb = fna 。当我们赋完值调用fnb时,实际上调用的是fna


let a = () => {
    console.log('a')
}
let b = () => {
    console.log(b)
}
b = a;
b() //a


所以fna中params:A又充当了我们的主类型,B是我们的子类型,B是A的子集,所以赋值成功!


双向协变



tsconfig中strictFunctionTypes 设置为false 支持双向协变 fna fnb 随便可以来回赋值,但是不推荐这么设置。


通过tsc --init生成配置项


fna = fnb
fnb = fna


image.png

目录
相关文章
|
JavaScript API
markdown-it 插件如何写(二)
「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。
510 0
markdown-it 插件如何写(二)
|
2月前
|
人工智能 自然语言处理 测试技术
Prompt Engineering 进阶:如何写出让 AI 自动生成高质量测试用例的提示词?
AI赋能测试用例设计,关键在结构化Prompt:需明确角色、业务、技术栈与约束,并融入等价类、状态图等测试方法论;要求表格化/代码化输出,辅以少样本示例和异常场景深挖。本质是将测试经验精准传递给AI。
|
28天前
|
前端开发 JavaScript 安全
前端开发者提效必看!阿里云/本地部署OpenClaw接入大模型免费API+搭建前端专项技能库实战指南
2026年,OpenClaw的Skills生态已成为前端开发者的“效率加速器”——ClawHub平台收录技能超17000款,但多数开发者仍停留在“安装即闲置”的困境。核心问题在于缺乏清晰的选型逻辑:前端开发场景多样(React/Vue/移动端/UI设计),盲目堆砌技能只会导致功能冲突、响应迟缓,反而降低效率。
539 1
|
数据采集 存储 调度
BeautifulSoup VS Scrapy:如何选择适合的HTML解析工具?
在Python网页抓取领域,BeautifulSoup和Scrapy是两款备受推崇的工具。BeautifulSoup易于上手、灵活性高,适合初学者和简单任务;Scrapy则是一个高效的爬虫框架,内置请求调度、数据存储等功能,适合大规模数据抓取和复杂逻辑处理。两者结合使用可以发挥各自优势,例如用Scrapy进行请求调度,用BeautifulSoup解析HTML。示例代码展示了如何在Scrapy中设置代理IP、User-Agent和Cookies,并使用BeautifulSoup解析响应内容。选择工具应根据项目需求,简单任务选BeautifulSoup,复杂任务选Scrapy。
384 1
BeautifulSoup VS Scrapy:如何选择适合的HTML解析工具?
|
9月前
|
存储 安全 NoSQL
【干货满满】API安全加固指南:签名防篡改+Access Token管理最佳实践
API 安全关乎业务与用户隐私,签名机制防篡改、伪造请求,Access Token 管理身份与权限。本文详解签名生成、Token 类型与管理、常见安全问题及最佳实践,助开发者构建安全可靠的 API 体系。
|
JSON JavaScript 前端开发
深入解析ESLint配置:从入门到精通的全方位指南,精细调优你的代码质量保障工具
深入解析ESLint配置:从入门到精通的全方位指南,精细调优你的代码质量保障工具
610 0
|
JavaScript
除了改变 key,还有哪些属性变化会触发组件重新渲染?
除了改变 key,还有哪些属性变化会触发组件重新渲染?
204 1
|
存储 应用服务中间件 PHP
设置nginx中文件上传的大小限制度
设置nginx中文件上传的大小限制度
|
存储 NoSQL 数据库
Oauth2协议中如何对accessToken进行校验
Oauth2协议中如何对accessToken进行校验
886 0
|
前端开发 开发者 容器
CSS进阶-Grid布局高级应用
【6月更文挑战第16天】**CSS Grid布局是CSS3的强大力量,用于复杂二维布局。然而,隐式网格、未命名Grid线和缺少响应式设计是常见问题。解决方法包括显式定义网格结构、命名Grid线和结合媒体查询实现响应式。高级技巧涉及自适应列宽、复杂区域布局和元素层叠对齐。代码示例展示了响应式Grid的用法。掌握这些能提升布局效率和设计灵活性。**
364 11