TS:子类型关系
子类型关系
- 1、概念
- 1.1 里氏替换原则
- 1.2 自反性
- 1.3 传递性
- 2、顶端类型 和 尾端类型
- 3、字面量类型
- 4、undefined 和 null
- 5、枚举类型
- 6、函数类型
- 6.1 变型
- 6.1.1 协变
- 6.1.2 逆变
- 6.1.3 双变
- 6.2 函数类型间的子类型关系
- 6.2.1 函数参数数量
- 6.2.2 函数参数类型
- A、非严格函数类型检查
- B、严格函数类型检查
- 6.2.3 函数返回值类型
- 6.2.4 函数重载
- 7、对象类型
- 7.1 属性成员类型
- 7.2 调用签名 和 构造签名
- 7.3 字符串索引签名 和 数值型索引签名
- 8、类类型
- 9、泛型类型
- 9.1 泛型对象类型
- 9.2 泛型函数类型
- 9.2.1 非严格泛型函数类型检查
- 9.2.2 严格泛型函数类型检查
- 10、联合类型 和 交叉类型
- 10.1 联合类型
- 10.2 交叉类型
1、概念
1.1 里氏替换原则
程序中任何使用了超类型 的地方都可以用其 子类型 进行替换,并且在替换后程序的行为保持不变。
1.2 自反性
任意类型都是其 自身 的子类型和超类型。
1.3 传递性
若 类型A 是 类型B 的子类型,且 类型B 是 类型C 的子类型,那么 类型A 也是 类型C 的子类型。
2、顶端类型 和 尾端类型
顶端类型是一种通用超类型,所有类型都是顶端类型的子类型;同时,尾端类型是所有类型的子类型。
TS 中存在两种顶端类型,即any类型和unknown类型。因此,所有类型都是any类型和unknown类型的子类型。
3、字面量类型
字面量类型是其对应的基础原始类型的子类型。
例如:maintainer 类型是 name 类型的子类型
type maintainer = 'Bob';
type name = 'string';
4、undefined 和 null
Undefined类型是 除尾端类型 never 外 所有类型的子类型,其中也包括null类型。
Null类型是 除尾端类型和undefined类型外 的所有类型的子类型。
5、枚举类型
在联合枚举类型中,每个枚举成员都能够表示一种类型,同时联合枚举成员类型是联合枚举类型的子类型。
什么是联合枚举类型?
枚举成员类型都是字面量类型的枚举类型。
6、函数类型
函数类型由 参数类型 和 返回值类型 构成。在比较两个函数类型间的子类型关系时要同时考虑 参数类型 和 返回值类型。
6.1 变型
在学习函数类型的字类型和超类型之间的关系前,我们要先了解一个和函数类型关系非常紧密的概念——变型。
所谓变型就是描述的是复杂类型的组成类型是如何影响复杂类型间的子类型关系的。
现约定如果复杂类型 Complex 是由 类型T 构成,那么我们将其记作 Complex(T)。
6.1.1 协变
假设有两个复杂类型 Complex(A) 和 Complex(B) ,如果由A是B的子类型能够得出 Complex(A) 是 Complex(B) 的子类型,那么我们将这种变型称作协变。
协变关系维持了复杂类型与其组成类型间的子类型关系。
6.1.2 逆变
如果由A是B的子类型能够得出 Complex(B) 是 Complex(A) 的子类型,那么我们将这种变型称作逆变。
6.1.3 双变
如果由 A 是 B 的子类型或者 B 是 A 的子类型能够得出 Complex(A) 是 Complex(B) 的子类型,那么我们将这种变型称作双变。
双变同时具有协变关系与逆变关系。
6.2 函数类型间的子类型关系
6.2.1 函数参数数量
子类型的 必选参数 的个数 不能多于 父类型 中的参数个数。
若函数类型 S 是函数类型 T 的子类型,则 S 中的每一个必选参数必须能够在T中找到对应的参数。
当T中存在 可选参数 或 剩余参数 时,函数类型检查是不可靠的。因为当使用子类型 S 替换了超类型 T 之后,调用 S 时的实际参数个数可能少于必选参数的个数。例如,有如下的函数s 和函数t ,其中 s 是 t 的子类型,使用一个实际参数调用函数 t 没有问题,但是将 t 替换为其子类型 s 后会产生错误,因为调用 s 需要两个实际参数。
function s(a: number, b: number): void {}
function t(...x:number[]): void {}t(0);
s(0); // 编译错误
6.2.2 函数参数类型
函数的参数类型会影响函数类型间的子类型关系。
A、非严格函数类型检查
在该模式下,函数参数类型与函数类型是 双变 关系。
若函数类型 S 是函数类型 T 的子类型,那么 S 的参数类型必须是 T 中对应参数类型的【子类型】或者【超类型】。这意味着在对应位置上的两个参数只要存在子类型关系即可,而不强调哪一方应该是另一方的子类型。
type S = (a: 0 | 1) => void;
type T = (x: number) => void;
此例中,S 是 T 的子类型,同时 T 也是 S 的子类型。
B、严格函数类型检查
strictFunctionTypes 编译选项用来启用严格的函数类型检查。
在该模式下,函数参数类型与函数类型是 逆变 关系,而非相对宽松的双变关系。
若函数类型 S 是函数类型 T 的子类型,那么 S 的参数类型必须是 T 中对应参数类型的 超类型。
6.2.3 函数返回值类型
在确定函数类型间的子类型关系时,编译器将检查函数返回值类型 是否兼容 。
不论是否启用了strictFunctionTypes 编译选项,函数返回值类型与函数类型始终是 协变 关系。
若函数类型 S 是函数类型 T 的子类型,那么 S 的返回值类型必须是 T 的返回值类型的 子类型。
我理解,无论是函数返回值类型还是严格模式下的函数参数类型检查,都要满足赋值兼容性,才符合里氏替换原则。
对于严格模式下的参数类型,超类型函数的实参要能赋值给子类型的形参。
对于函数返回值类型,子类型函数的返回值要能赋值给超类型函数的返回值。
6.2.4 函数重载
在确定函数类型间的子类型关系时,编译器将检查函数重载签名类型是否兼容。
若函数类型 S 是函数类型 T 的子类型,并且 T 存在函数重载,那么 T 的每一个函数重载必须能够在 S 的函数重载中找到与其对应的子类型。
7、对象类型
在比较对象类型的子类型关系时要分别考虑 每一个 类型成员。
在结构化子类型系统中仅通过比较两个对象类型的 类型成员列表 就能够确定它们的子类型关系。对象类型的名称完全不影响对象类型间的子类型关系。
例如,以下示例中 类型 A 和 类型 B 是相同类型,类型 C 是 类型 A 和 类型 B 的超类型。
type A = {name: string,age: number
}
type B = {name: string,age: number
}
type C = {name: string
}
对象类型的子类型关系要满足以下条件:
- 在数量上,超类型对象类型的成员数量不能多于 子类型对象类型的成员数量。
- 在属性成员的可访问性上,超类型中的必选属性在子类型中也必须是必选属性。
- 在成员类型上,子类型的成员类型是超类型中对应的成员类型的子类型。
7.1 属性成员类型
超类型的每个属性成员 M 都能够在子类型中找到同名属性成员 N,且 N 是 M 的子类型。
7.2 调用签名 和 构造签名
超类型中的调用签名 M 都能够在子类型中找到对应的调用签名 N,且 N 是 M 的子类型。
对象类型中的构造签名与调用签名有着相同的判断规则。
7.3 字符串索引签名 和 数值型索引签名
父类型中有索引签名,子类型中也要有,并子类型的索引签名类型是父类型索引签名类型的子类型。
8、类类型
在确定两个类类型之间的子类型关系时,仅检查类的 实例成员 类型,类的 静态成员类型 以及 构造函数类型 不进行检查。
如果类中存在 私有成员 或 受保护成员,那么在确定类类型间的子类型关系时要求私有成员和受保护成员 来自同一个类,这意味着两个类需要存在 继承关系。
例如,以下代码中,Point 和 Position 中的受保护成员 x 都来自Point,因此 Position 是 Point 的子类型。
class Point {protected x: number = 0;
}
class position extends Point {protected y: number = 0;
}
9、泛型类型
9.1 泛型对象类型
对于泛型接口、泛型类和表示对象类型的泛型类型别名而言,实例化泛型类型时使用的实际类型参数 不影响 子类型关系,真正影响子类型关系的是泛型实例化后的 结果对象类型。
9.2 泛型函数类型
TS编译器提供了noStrictGenericChecks 编译选项用来启用或关闭严格泛型函数类型检查。
9.2.1 非严格泛型函数类型检查
编译器先将所有的泛型类型参数替换为 any 类型,然后再确定子类型关系。这意味着泛型类型参数不影响泛型函数的子类型关系。
type A = <T, U>(x: T, y: U) => [T, U];
type B = <S>(x: S, y: S) => [S, S];
将所有的类型参数替换为any类型,结果如下:
type A = (x: any, y: any) => [any, any];
type B = (x: any, y: any) => [any, any];
9.2.2 严格泛型函数类型检查
先通过类型推断来 统一 两个泛型函数的类型参数,然后再确定两者的子类型关系。
type A = <T, U>(x: T, y: U) => [T, U];
type B = <S>(x: S, y: S) => [S, S];
如果我们想要确定 A 是否为 B 的子类型,那么先尝试使用 B 的类型来推断A的类型。通过比较每个参数类型和返回值类型,能够得出类型参数 T 和 U 均为 S。接下来使用推断的结果来实例化 A 类型,即将类型 A 中的 T 和 U 均替换为 S,替换后的结果如下:
type A = <S>(x: S, y: S) => [S, S];
type B = <S>(x: S, y: S) => [S, S];
在统一了类型参数之后,再来比较泛型函数间的子类型关系。因为统一后的类型 A 和 B 相同,所以 A 是 B 的子类型。
如果我们最开始想要确定 B 是否为 A 的子类型,那么这时将由 A 向 B 来推断并统一类型参数的值。经推断,S 的类型为联合类型“T | U”,然后使用“S = T | U”来实例化 B 类型,结果如下:
type A = <T, U>(x: T, y: U) => [T, U];
type B = <T, U>(x: T | U, y: T | U) => [T | U, T | U];
此时,B 不是 A 的子类型,因为 B 的返回值类型不是 A 的返回值类型的子类型。
10、联合类型 和 交叉类型
10.1 联合类型
联合类型由若干成员类型构成,在计算联合类型的子类型关系时需要考虑每一个成员类型。
假设有联合类型 S = S0 | S1 和任意类型 T,如果成员类型 S0 是类型 T 的子类型,并且成员类型 S1 是类型 T 的子类型,那么联合类型 S 是类型 T 的子类型。例如,有如下定义的联合类型 S 和类型 T 。
type S = 0 | 1;
type T = number;
此例中,联合类型 S 是类型 T 的子类型。
假设有联合类型 S = S0 | S1 和任意类型 T,如果类型 T 是成员类型 S0 的子类型,或者类型T是成员类型 S1 的子类型,那么类型 T 是联合类型 S 的子类型。例如,有如下定义的联合类型 S 和类型 T :
type S = number | string;
type T = 0;
此例中,类型T是联合类型S的子类型。
10.2 交叉类型
交叉类型由若干成员类型构成,在计算交叉类型的子类型关系时需要考虑每一个成员类型。
假设有交叉类型 S = S0 & S1 和任意类型 T,如果成员类型 S0 是类型 T 的子类型,或者成员类型 S1 是类型 T 的子类型,那么交叉类型 S 是类型 T 的子类型。
type S = { x: number } & { y: number };
type T = { x: number };
假设有交叉类型 S = S0 & S1 和任意类型 T,如果类型 T 是成员类型 S0 的子类型,并且类型 T 是成员类型 S1 的子类型,那么类型 T 是交叉类型 S 的子类型。
type S = { x: number } & { y: number };
type T = { x: number; y: number; z: number };
相关文章:
TS:子类型关系
子类型关系 1、概念1.1 里氏替换原则1.2 自反性1.3 传递性 2、顶端类型 和 尾端类型3、字面量类型4、undefined 和 null5、枚举类型6、函数类型6.1 变型6.1.1 协变6.1.2 逆变6.1.3 双变 6.2 函数类型间的子类型关系6.2.1 函数参数数量6.2.2 函数参数类型A、非严格函数类型检查B…...
IDEA插件(MyBatis Log Free)
引言 在Java开发中,MyBatis 是一款广泛使用的持久层框架,它简化了SQL映射并提供了强大的数据访问能力。为了更好地调试和优化MyBatis应用中的SQL语句执行,一款名为 MyBatis Log Free 的 IntelliJ IDEA 插件应运而生。这款插件旨在帮助开发者…...
Redis(八)哨兵机制(sentinel)
文章目录 哨兵机制案例认识异常 哨兵运行流程及选举原理主观下线(Subjectively Down)ODown客观下线(Objectively Down)选举出领导者哨兵选出新master过程 哨兵使用建议 哨兵机制 吹哨人巡查监控后台master主机是否故障,如果故障了根据投票数自动将某一个从库转换为新…...
[数据结构]-哈希
前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 本期学习目标&…...
宝塔控制面板配置SSL证书实现网站HTTPS
宝塔安装SSL证书提前申请好SSL证书,如果还没有,先去Gworg里面申请,一般几分钟就可以下来,申请地址:首页-Gworg官方店-淘宝网 一、登录邮箱下载:Gworg证书文件目录 ,都会有以下五个文件夹。宝塔…...
elasticsearch优化总结
参考: https://docs.docker.com/manuals/ Manuals | Docker Docs Run Elasticsearch locally | Elasticsearch Guide [8.12] | Elastic 让你的ES查询性能起飞:Elasticsearch 查询优化攻略“一网打尽” - 知乎...
图论第三天|127. 单词接龙 841.钥匙和房间 463. 岛屿的周长 1971. 寻找图中是否存在路径 684.冗余连接 685.冗余连接II
目录 Leetcode127. 单词接龙Leetcode841.钥匙和房间Leetcode463. 岛屿的周长Leetcode1971. 寻找图中是否存在路径Leetcode684.冗余连接Leetcode685.冗余连接II Leetcode127. 单词接龙 文章链接:代码随想录 题目链接:127. 单词接龙 思路:广搜搜…...
react的高阶函数HOC:
React 的高阶组件(Higher-Order Component,HOC)是一种用于复用组件逻辑的模式。它是一个函数,接收一个组件作为参数,并返回一个新的增强过的组件。 HOC 可以用于实现以下功能: 代码复用:通过将…...
STM32——中断系统和外部中断EXTI
一、中断 1.1中断系统 中断系统是管理和执行中断的逻辑结构; 1.2中断 系统在执行主程序过程中,出现了特定的触发条件(触发源),系统停止执行当前程序,转而去执行中断程序,执行完毕后…...
使用uniApp+vue3+Vite4+pinia+sass技术栈构建微信小程序
使用uniApp的cli模式安装,可以使用vscode开发。不用再单独去下载HBuilderX. 1.基础安装 vue3tsuniapp 方法一: npx degit dcloudio/uni-preset-vue#vite-ts my-vue3-project方法二:可以去uni-preset-vue的vite分支下选择vite-ts直接下载zi…...
npm 被滥用 -- 有人上传了 700 多个武林外传切片视频
Sonatype 安全研究团队最近曝光了一起滥用 npm 的案例 —— 他们发现在 npm 上托管的 748 个软件包实际上是视频文件。 据介绍,这些软件包每个大小约为 54.5MB,包名以 “wlwz” 为前缀,并附带了代表日期的数字。根据时间戳显示,这…...
代码随想录算法训练营29期|day34 任务以及具体任务
第八章 贪心算法 part03 1005.K次取反后最大化的数组和 class Solution {public int largestSumAfterKNegations(int[] nums, int K) {// 将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小nums IntStream.of(nums).boxed().sorted((o1, o2) -> Math.ab…...
LeetCode 每日一题 2024/1/22-2024/1/28
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 1/22 670. 最大交换1/23 2765. 最长交替子数组1/24 2865. 美丽塔 I1/25 2859. 计算 K 置位下标对应元素的和1/26 2846. 边权重均等查询1/27 2861. 最大合金数1/28 365. 水壶…...
好用的学习与开发工具
1. 首推 UTools 官网地址 uTools官网 - 新一代效率工具平台 介绍 uTools 是一个极简、插件化的现代桌面软件,通过自由选配丰富的插件,打造得心应手的工具集合。 通过快捷键(默认 alt space )就可以快速呼出这个搜索框。你可…...
(自用)learnOpenGL学习总结-高级OpenGL-立方体贴图
ok终于来到了立方体贴图了,在这里面我们可以加入好看的天空包围盒,这样的画我们的背景就不再是黑色的了! 首先,立方体贴图和前面的sampler2D贴图一样,不过是6个2D组成的立方体而已。 那么为什么要把6个组合在一起呢&…...
【计算机网络】——TCP协议
📑前言 本文主要是【计算机网络】——传输层TCP协议的文章,如果有什么需要改进的地方还请大佬指出⛺️ 🎬作者简介:大家好,我是青衿🥇 ☁️博客首页:CSDN主页放风讲故事 🌄每日一句…...
sql优化的方法
目录 一、准备数据 1.1、创建表结构 1.2、创建存储过程 二、索引介绍 2.1、类型介绍 2.2、建立索引 2.3、建立复合索引 2.4、查看所有建立的索引 2.5、删除索引 三、EXPLAIN分析参数说明 四、SQL优化案例 4.1、避免使用SELECT * 4.2、慎用UNION关键字 4.4、避免使…...
C++ Qt开发:运用QJSON模块解析数据
Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QJson组件的实现对JSON文本的灵活解析…...
MySQL数据库基础合集
MySQL数据库基础合集 目录 MySQL数据库基础合集SQL关键字DDL关键字DML关键字DQL关键字DCL关键字约束关键字 SQL基础数据类型整数类型字符类型浮点类型时间类型 数据定义语言DDL1.查看数据库2.创建库3.删除库4.切换库5.创建表6.删除表7.查看表8.查看表属性9.插入列10.修改列11.设…...
oracle19.22的patch已发布
2024年01月16日,oracle发布了19.22的patch 具体patch如下 Reserved for Database - Do not edit or delete (Doc ID 19202401.9) 文档ID规则如下 19(版本)年份(202x)(季度首月01,04,07,10).9 往期patch no信息和下…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
