让我百思不得其解的infer究竟是怎么推导类型的?
情景再现
有这么一个条件类型的基本语法:
T extends U ? X : Y;
如果占位符类型U
是一个可以被分解成几个部分的类型,譬如数组类型,元组类型,函数类型,字符串字面量类型等。这时候就可以通过infer
来获取U
类型中某个部分的类型。
我们再看看下面的这个例子
type InferArray<T> = T extends Array<infer U> ? U : never;
使用
type I1 = InferArray<[string, number, true]>; // string
type T0 = InferArray<string> // never
推断结果
我们使用infer
关键字声明性地引入了一个名为的新泛型类型变量infer U
表示待推断的函数参数 。整句的意思为:如果 T
能 赋值给 Array<infer U>
,则结果是Array<infer U>
里的类型U
,否则返回never
。
从上面可以看出,只要是我们传入的时候是数组string[]
,无论你传入什么类型,它都给你推导出来,如果是只传递了string
,这时候推导的它根本不是个数组,条件判断为false
,直接返回never
。
相信通过上面这个粗俗又晦涩例子大家可以明白infer
到底能干嘛,以及在什么时候干,大家只需要记住下面的两点:
infer
语法的限制如下:1.
infer
只能在条件类型的 extends 子句中使用
2.infer
得到的类型只能在true
语句中使用, 即X
中使用
初试牛刀
下面我们来看一道类型体操题目来加深一下infer的用法。
题目:
type TupleA = [number, boolean, string]
type TupleB = [boolean, string, number, unknown?]
type TupleC = [number, number, boolean, boolean]
问题:
这里有3个元组类型,取出元组类型的第二项,取到的第二项类型是什么?
分析:
虽然看上面的三个元祖类型很少,一眼就看出来里面的第二项是什么类型,但是,如果给你几百个几千个呢?这时候就需要我们使用infer来解决了。
首先
type Second<xxx> = xxx
第一个xxx参数,泛型这里肯定传的就是不一样的元组类型;第二个xxx就是我们实现的过程,我们要取元组的第二项的类型!
先来写第一个xxx,毕竟比较简单,元组就是个特殊的数组,我们并不知道数组的每一项会是什么类型,所以可以这么写
type Second<Tuple extends unknown[]> = xxx
第一步完成,这个extends就是限制了我们传入的元组类型,不知道的数组类型(PS:注意我们unknown
类型是除了any
以外最底层的)。
紧接着第二步,我们就要用到infer了,还要用到extends的另外一种用法,条件判断,具体代码如下:
type Second<Tuple extends unknown[]> = Tuple extends [infer A, infer B, ...infer C] ? B : never
简单的说,我们这边分别用infer占位了,第一项A,第二项B,然后用展开运算,剩余项用C表示,如果符合了我们这个条件,返回就是B,即第二项,否则就不返回!
题做完了,我们来验证一下答案是否正确:
最终答案:
type TupleA = [number, boolean, string]
type TupleB = [boolean, string, number, unknown?]
type TupleC = [number, number, boolean, boolean]type Second<Tuple extends unknown[]> = Tuple extends [infer A, infer B, ...infer C] ? B : nevertype SecondA = Second<TupleA>
type SecondB = Second<TupleB>
type SecondC = Second<TupleC>
使用场景
1.推断数组(或者元组)的类型
type InferArray<T> = T extends (infer U)[] ? U : never;
(infer U)
和平时常写的string[]
,number[]
等等是不是很像?这里就是通过(infer U)
来获取数组对应的类型。
type I0 = InferArray<[number, string]>; // string | number
type I1 = InferArray<string[]>; // string
type I2 = InferArray<number[]>; // number
2.推断数组(或者元组)第一个元素的类型
type InferFirst<T extends unknown[]> = T extends [infer P, ...infer _] ? P : never
[infer P, ... infer _]
中infer P获取的
是第一个元素的类型,而...infer _
获取的是数组其他剩余元素的数组类型;> 特别说明下,我们例子汇总不需要使用其他元素的类型,所以用_
。
type I3 = InferFirst<[3, 2, 1]>; // 3
3.推断数组(或者元组)最后一个元素的类型
type InferLast<T extends unknown[]> = T extends [... infer _, infer Last] ? Last : never;
这个和推断数组第一个元素的类型类似,
...infer _
获取的是最后一个元素之前的所有元素类型,infer Last
获取的是最后一个元素的类型。
type I4 = InferLast<[3, 2, 1]>; // 1
4.推断函数类型的参数
type InferParameters<T extends Function> = T extends (...args: infer R) => any ? R : never;
...args
代表的是函数参数组成的元组,infer R
代表的就是推断出来的这个函数参数组成的元组的类型。
type I5 = InferParameters<((arg1: string, arg2: number) => void)>; // [string, number]
5.推断函数类型的返回值
type InferReturnType<T extends Function> = T extends (...args: any) => infer R ? R : never;
和前面的推断函数类型的参数
类似,=>
后面的infer R
代表的就是推断出来的函数的返回值类型。
type I6 = InferReturnType<() => string>; // string
6.推断Promise成功值的类型
type InferPromise<T> =T extends Promise<infer U> ? U : never;
type I7 = InferPromise<Promise<string>>; // string
7.推断字符串字面量类型的第一个字符对应的字面量类型
type InferString<T extends string> = T extends `${infer First}${infer _}` ? First : [];
type I8 = InferString<"xiumubai">; // J
出师时刻
接下来我举一些综合性的例子,大家来感受下infer
的使用技巧,看看是否能一眼看出来实现的功能,可以按照对应的题目顺序在评论区留言
// Q1
type Shift<T> = T extends [infer L, ...infer R]? [...R] : [];
// A:?
// Q2
type Pop<T extends any[]> = T extends [...infer L, infer R] ? [...L] : [];
// A:?
// Q3
type Reverse<T extends unknown[], U extends unknown[] = []> = [] extends T? U: T extends [infer L, ...infer R]? Reverse<R, [L, ...U]>: U;
// A:?
// Q4
type FlipArguments<T extends Function> = T extends (...arg: infer R) => infer S ? (...arg : Reverse<[...R]>) => S : T;
: T extends [infer L, ...infer R]? Reverse<R, [L, ...U]>: U;
// A:?
// Q4
type FlipArguments<T extends Function> = T extends (...arg: infer R) => infer S ? (...arg : Reverse<[...R]>) => S : T;
最后
最近找到一个VUE的文档,它将VUE的各个知识点进行了总结,整理成了《Vue 开发必须知道的36个技巧》。内容比较详实,对各个知识点的讲解也十分到位。
有需要的小伙伴,可以点击下方卡片领取,无偿分享
相关文章:
让我百思不得其解的infer究竟是怎么推导类型的?
情景再现 有这么一个条件类型的基本语法: T extends U ? X : Y; 如果占位符类型U是一个可以被分解成几个部分的类型,譬如数组类型,元组类型,函数类型,字符串字面量类型等。这时候就可以通过infer来获取U类型中某个部分的类型。 …...
E8-怎么实现根据表单内容自动生成标题
背景 可能有些小伙伴看到这个话题,觉得非常简单,在发起人步骤设置标题可编辑,在有关的控件中设置事件去更新标题就可以了呗。但如果想要标题字段里包含编号呢,而编号是在具体路径的高级设置里设置的,在某个出口生成的…...
《c语言深度解剖》--一套非常经典的笔试题
学习完c语言,需要对所学知识进行一个检测,下面有一套笔试题, 你有四十分钟进行检测,每道题五分,严格要求自己打分。 根据作者原话:在没有何提示的情况下,如果能得满分,那你可以扔掉本书了,因为你的水平已经…...
【数据结构与算法】单调队列 | 单调栈
🌠作者:阿亮joy. 🎆专栏:《数据结构与算法要啸着学》 🎇座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉…...
openh264解码h264视频帧主流程
一 解析一帧的入口int32_t WelsDecodeSlice (PWelsDecoderContext pCtx, bool bFirstSliceInLayer, PNalUnit pNalCur) {// 解码slicePDqLayer pCurDqLayer pCtx->pCurDqLayer;PFmo pFmo pCtx->pFmo;int32_t iRet;int32_t iNextMbXyIndex, iSliceIdc;PSlice pSlice &a…...
【个人笔记】C语言位域
一句话解释位域:指定结构体内变量的的位宽,从而节省空间 例子: #include <stdio.h> struct _test {int bit1:3; // 第一个字节0 ~ 2位 int :0; // 空域:表示第一个字节 3~7都为0int bit2:1; // 第二个字节第0位int :3;…...
ROS笔记(1)——ROS的核心概念
目录 节点与管理器 话题通信 服务通信 参数——全局共享字典 节点与管理器 节点——执行单元 (1)执行具体任务的进程、独立运行的可执行文件 (2)不同节点可使用不同的编程语言,可分布式运行在不同的主机 ÿ…...
动态SQL使用【JavaEE】
动态SQL使用 1. if 标签 判断一个参数是否有值,如果没值,那么就会隐藏 if 中的 sql 语法: <if test"username!null">username#{username} </if>表达式:username 的参数是否为空 如果结果为 true,…...
leetcode刷题
1、stack栈相关 top():返回一个栈顶元素的引用,类型为 T&。如果栈为空,返回值未定义。 push(const T& obj):可以将对象副本压入栈顶。这是通过调用底层容器的 push_back() 函数完成的。 push(T&& obj)࿱…...
移动设备安全管理基础指南
什么是移动安全管理 (MSM) 移动安全管理是指为保护企业中的移动设备和企业数据而采取的行动。这些操作可以进一步被归类为反应性的或主动的,基于该操作是在数据和设备被破坏之前还是之后执行的。除了管理移动设备外,大多数MDM解决…...
【Java|多线程与高并发】 使用Thread 类创建线程的5种方法如何查看程序中的线程
文章目录前言线程创建1.继承Thread类重写run()方法如何查看程序中的线程?2.实现Runnable接口3.使用匿名内部类,继承Thread4.使用匿名内部类,实现Runnable5.⭐使用Lambda表达式,创建线程(重要)Thread 的常见构造方法总结前言 在这里主要补充说明一些问题,方便更好地理解下面的…...
零基础学MySQL(五)-- 详细讲解数据库中的常用函数
目录🎇一、聚合函数1️⃣count 函数(1)基本语法(2)基本练习(3)注意细节2️⃣sum 函数(1)基本语法(2)基本练习(3)注意细节3…...
第4章 流程控制-if-else,Switch,For循环(循环守卫,循环步长,倒叙打印),While循环,多重循环...
第 4 章 流程控制-if-else,Switch,For循环(循环守卫,循环步长,倒叙打印),While循环,多重循环 4.1 分支控制 if-else 让程序有选择的的执行,分支控制有三种:单分支、双分支、多分支 4.1.1 单分支 1)基本语法…...
2.4G-WiFi连接路由器过程
一、概述 WiFi的数据通信基于802.11协议进行,无线AP在工作时会定时向空中发送beacon数据包,基站(STA)从beacon中解析出AP的名称、加密方式等信息,从而发起连接。 二、WiFi连接路由器的详细过程 WiFi连接过程主要可以…...
3. SpringMVC Rest 风格
1. REST 简介 REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格。 当要表示一个网络资源的时候,可以使用两种方式: 传统风格资源描述形式 http://localhost/user/getById?…...
Python3简介
Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。 Python 的设计具有很强的可读性,相比其他语言经常使用英文关键字,其他语言的一些标点符号,它具有比其他语言更有特色语法结构。 Python 是面向对象语言: 这意味着P…...
如何学习PMP?
★基础要打牢 方法:“基础不牢,地动山摇”,如果基础不牢那么就很难拿高分,因为连最基础的题目分都不一定能拿到。 可以在针对基础知识,把PMBOK看一两遍,再次加深印象,再把平时做章节练习、每日5…...
【DSP视频教程】第11期:插补算法,曲线拟合丝滑顺畅,统计函数和基础函数加速实现,汇集SIMD,饱和和MAC乘累加应用实战(2023-02-12)
视频教程汇总帖:https://www.armbbs.cn/forum.php?modviewthread&tid110519 DSP视频教程有段时间没有更新了。 当前DSP库从CMSIS软件包里面独立出来,并且更新非常频繁,所以本期视频教程优先给大家简单介绍下新版DSP, 然后为…...
分类模型评估:混淆矩阵、准确率、召回率、ROC
1. 混淆矩阵 在二分类问题中,混淆矩阵被用来度量模型的准确率。因为在二分类问题中单一样本的预测结果只有Yes or No,即:真或者假两种结果,所以全体样本的经二分类模型处理后,处理结果不外乎四种情况,每种…...
算法 ——世界 一
个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。个人爱好: 编程,打篮球,计算机知识个人名言:海不辞水,故能成其大;山不辞石…...
2023年3月AMA-CDGA/CDGP数据治理认证考试这些城市可以报名
目前2023年3月5日CDGA&CDGP开放报名的城市有:北京、上海、广州、深圳、杭州、重庆,西安,成都,长沙,济南,更多考场正在增加中… DAMA认证为数据管理专业人士提供职业目标晋升规划,彰显了职业…...
Java变量和数据类型,超详细整理,适合新手入门
目录 一、什么是变量? 二、变量 变量值互换 三、基本数据类型 1、八种基本数据类型 2、布尔值 3、字符串 四、从控制台输入 一、什么是变量? 变量是一种存储值的容器,它可以在程序的不同部分之间共享;变量可以存储数字、字…...
Echarts 设置折线图拐点的颜色,边框等样式,hover时改变颜色
第014个点击查看专栏目录上一篇文章我们讲到了如何设置拐点大小,图形类型,旋转角度,缩放同比,位置偏移等,这篇文章介绍如何设置拐点的颜色、边框大小颜色等样式。hover轴线时候,拐点的填充颜色改变文章目录示例效果示例…...
做 SQL 性能优化真是让人干瞪眼
很多大数据计算都是用SQL实现的,跑得慢时就要去优化SQL,但常常碰到让人干瞪眼的情况。 比如,存储过程中有三条大概形如这样的语句执行得很慢: select a,b,sum(x) from T group by a,b where …; select c,d,max(y) from T grou…...
SpringBoot(3)之包结构
根据spring可知道,注解之所以可以使用,是因为通过包扫描器,扫描包,然后才能通过注解开发。 那么springboot需要扫描哪里呢? springboot的默认包扫描器,扫描的是自己所在的包和子包,例子如下 我…...
test2
物理层故障分析 一、传输介质故障 a.主要用途简述 传输介质主要分为 导向传输介质和非导向传输介质。前者包括双绞线(两根铜线并排绞合,距离过远会失真)、同轴电缆(铜质芯线屏蔽层,抗干扰性强,传输距离更…...
LoadRunner安装教程
备注:电脑最好安装有IE浏览器或者360极速版浏览器 一、下载安装包 提前下载安装文件,必须下载。 链接: https://pan.baidu.com/s/1blFiMIJcoE8s3uVhAxdzdA?pwdqhpt 提取码: qhpt 包含的文件有: 二、安装loadrunner 注意,以…...
VHDL语言基础-Testbech
目录 VHDL仿真概述: 基本结构: VHDL一般仿真过程: 仿真测试平台文件: 编写测试平台文件的语言: 一个测试平台文件的基本结构如下: 测试平台文件包含的基本语句: 产生激励信号的方式: 时钟信号: 复位信号: 周期信性信号: 使用延迟DELAYD: 一般的激励信号…...
机器学习基础总结
一,机器学习系统分类 机器学习系统分为三个类别,如下图所示: 二,如何处理数据中的缺失值 可以分为以下 2 种情况: 缺失值较多:直接舍弃该列特征,否则可能会带来较大噪声,从而对结果造成不良影…...
linux的三权分立设计思路和用户创建(安全管理员、系统管理员和审计管理员)
目录 一、三权分立设计思路 1、什么是三权 2、三员及权限的理解 3、三员之三权 4、权限划分 5、“三员”职责 6、“三员”配置要求 二、linux三权分立的用户创建 1、系统管理员 2、安全管理员 3、审计管理员 一、三权分立设计思路 1、什么是三权 三权指的是配置、…...
做网站难吗 挣钱吗/百度做网站
最近遇到一个问题:服务器被全球的IP频繁试图通过ssh登录。 于是想到通过iptables防火墙限制访问,达到:仅允许指定ip段访问ssh服务(22端口)。 关于iptables添加规则的文章有很多,而鲜有介绍规则之间的顺序。因此希望通过这篇文章介…...
茂港网站建设公司/信息流广告公司一级代理
今天在查看AWR报告时,发现里面很多sql都有/ OPAQUE_TRANSFORM / 觉得很奇怪,所以就上MOS上查了一下,以下内容基于原文翻译 (Doc ID 780503.1). What is OPAQUE_TRANSFORM usage : The OPAQUE_TRANSFORM hint is to help with the transforma…...
wordpress 滚动条/宣传广告怎么做吸引人
Python3ScrapyphantomJsSelenium爬取今日头条 在实现爬虫的过程中,我们不可避免的会爬取又JS以及Ajax等动态网页技术生成网页内容的网站,今日头条就是一个很好的例子。 本文所要介绍的是基于Python3,配合Scrapyphantomjsselenium框架的动态…...
网站内容的编辑和更新怎么做/关键词研究工具
Items Override 覆写Overload 重载位置存在于继承关系的类中存在于同一类中 方法名相同相同参数列表相同必须不同 返回值相同可以不相同 程序中的处理程序运行时 程序编译时 抽象方法使用abstract关键字 public abstract bool Withdraw(…);抽象方法是必须被派生类覆写的方法。…...
网站建设 检查 通报/河源疫情最新通报
外观模式 为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 外观模式三要素(client-facade-subSystem) 外观角色(facade),是模式的…...
开放大学门户网站建设/互联网营销平台
请完成Java程序:本题是一个冒泡排序程序的实例。冒泡排序的含义是将相邻的两个数作比较,如果是升序排列的话,如果前边的数大,则将两个数交换。从第一个数开始两两比较一次,就可以将最大的数移动到最后。注意࿱…...