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

目录
相关文章
electron解决创建新窗口html文件不能引入ipcRenderer通信
electron解决创建新窗口html文件不能引入ipcRenderer通信
|
API 索引 数据处理
【鸿蒙软件开发】ArkTS基础组件之Select(下拉菜单)、Slider(滑动条)
【鸿蒙软件开发】ArkTS基础组件之Select(下拉菜单)、Slider(滑动条)
2929 0
【鸿蒙软件开发】ArkTS基础组件之Select(下拉菜单)、Slider(滑动条)
|
2月前
|
存储 安全 NoSQL
【干货满满】API安全加固指南:签名防篡改+Access Token管理最佳实践
API 安全关乎业务与用户隐私,签名机制防篡改、伪造请求,Access Token 管理身份与权限。本文详解签名生成、Token 类型与管理、常见安全问题及最佳实践,助开发者构建安全可靠的 API 体系。
|
小程序 安全 JavaScript
【微信小程序】-- uni-app 项目创建 & 目录结构讲解(四十九)
【微信小程序】-- uni-app 项目创建 & 目录结构讲解(四十九)
|
并行计算 PyTorch 算法框架/工具
LLM推理引擎怎么选?TensorRT vs vLLM vs LMDeploy vs MLC-LLM
有很多个框架和包可以优化LLM推理和服务,所以在本文中我将整理一些常用的推理引擎并进行比较。
1689 2
|
缓存 JavaScript 前端开发
|
前端开发 开发者 容器
CSS进阶-Grid布局高级应用
【6月更文挑战第16天】**CSS Grid布局是CSS3的强大力量,用于复杂二维布局。然而,隐式网格、未命名Grid线和缺少响应式设计是常见问题。解决方法包括显式定义网格结构、命名Grid线和结合媒体查询实现响应式。高级技巧涉及自适应列宽、复杂区域布局和元素层叠对齐。代码示例展示了响应式Grid的用法。掌握这些能提升布局效率和设计灵活性。**
215 11
|
设计模式 JavaScript 算法
js设计模式【详解】—— 策略模式
js设计模式【详解】—— 策略模式
163 0
|
存储 NoSQL 数据库
Oauth2协议中如何对accessToken进行校验
Oauth2协议中如何对accessToken进行校验
675 0
|
存储 缓存 前端开发
前端如何利用indexDB进行数据优化
使用IndexedDB作为浏览器内置的客户端数据库,用于存储大量数据和实现离线支持。它能缓存常用数据,减少服务器请求,提高用户体验。IndexedDB支持数据索引、复杂查询及版本管理,允许离线操作并同步到服务器。但需熟悉其异步API,可借助Dexie.js、localForage等库简化使用。