TS类型体操图解一个复杂高级类型
之前我们零散地了解了一些 TypeScript 类型体操的套路,但是没有综合练习下,今天就来做个高难度的体操,它会综合运用模式匹配、构造、递归等套路,对提升类型编程水平很有帮助。
我们要实现的高级类型如下:
图片
它的类型参数是参数字符串 query string,会返回解析出的参数对象,如果有同名的参数,会把值做合并。
先不着急实现,我们先回顾下相关的类型体操基础:
类型体操基础
模式匹配
模式匹配是指用一个类型匹配一个模式类型来提取其中的部分类型到 infer 声明的局部变量中。
比如提取 a=b 中的 a 和 b:
图片
这种模式匹配的套路在数组、字符串、函数等类型中都有很多应用。
详细了解可以看之前的一篇文章:模式匹配-让你 ts 类型体操水平暴增的套路
构造
映射类型用于生成索引类型,生成的过程中可以对索引或者索引值做一些修改。
比如指定 key 和 value 来生成一个索引类型:
图片
详细了解可以看之前的一篇文章:TS 类型体操:索引类型的映射再映射
递归
TypeScript 高级类型支持递归,可以处理数量不确定的问题。
比如不确定长度的字符串的反转:
type ReverseStr<
Str extends string,
Result extends string = ""
> = Str extends `${infer First}${infer Rest}`
? ReverseStr
: Result;
图片
简单了解下模式匹配、构造、递归都是什么之后,就可以开始实现这个复杂的高级类型 ParseQueryString 了:
思路分析
假设有这样一个 query string:a=1&a=2&b=3&c=4。
我们要首先把它分成 4 部分:也就是 a=1、a=2、b=3、c=4。这个就是用通过上面讲的模式匹配来提取。
每一部分又可以进一步处理,提取出 key value 构造成索引类型,比如 a=1 就可以通过模式匹配提取出 a、1,然后构造成索引类型 {a: 1}。
这样就有了 4 个索引类型 {a:1}、{a:2}、{b:3}、{c:4}。
结下来把它合并成一个就可以了,合并的时候如果有相同的 key 的值,要放到数组里。
就产生了最终的索引类型:{a: [1,2], b: 3, c: 4}
整体流程是这样的:
图片
其中第一步并不知道有多少个 a=1、b=2 这种 query param,所以要递归的做模式匹配来提取。
这就是这个高级类型的实现思路。
下面我们具体来写一下:
代码实现
我们按照上图的顺序来实现,首先提取 query string 中的每一个 query param:
图片
query param 数量不确定,所以要用递归:
type ParseQueryString
= Str extends `${infer Param}&${infer Rest}`
? MergeParams, ParseQueryString>
: ParseParam;
类型参数 Str 为待处理的 query string。
通过模式匹配提取其中第一个 query param 到 infer 声明的局部变量 Param 中,剩余的字符串放到 Rest 中。
用 ParseParam 来处理 Param,剩余的递归处理,最后把它们合并到一起,也就是 MergeParams 。
如果模式匹配不满足,说明还剩下最后一个 query param 了,也用 ParseParam 处理。
然后分别实现每一个 query param 的 parse:
图片
这个就是用模式匹配提取 key 和 value,然后构造一个索引类型:
type ParseParam
= Param extends `${infer Key}=${infer Value}`
? { [K in Key]: Value }
: {};
这里构造索引类型用的就是映射类型的语法。
先来测试下这个 ParseParam:
图片
做完每一个 query param 的解析了,之后把它们合并到一起就行:
图片
合并的部分就是 MergeParams:
type MergeParams<
OneParam extends object,
OtherParam extends object
> = {
[Key in keyof OneParam | keyof OtherParam]:
Key extends keyof OneParam
? Key extends keyof OtherParam
? MergeValues
: OneParam[Key]
: Key extends keyof OtherParam
? OtherParam[Key]
: never
}
两个索引类型的合并也是要用映射类型的语法构造一个新的索引类型。
key 是取自两者也就是 key in keyof OneParam | keyof OtherParam。
value 要分两种情况:
如果两个索引类型都有的 key,就要做合并,也就是 MergeValues。
如果只有其中一个索引类型有,那就取它的值,也就是 OtherParam[key] 或者 OneParam[Key]。
合并的时候,如果两者一样就返回任意一个,如果不一样,就合并到数组里返回,也就是 [One, Other]。如果本来是数组的话,那就是数组的合并 [One, ...Other]。
type MergeValues =
One extends Other
? One
: Other extends unknown[]
? [One, ...Other]
: [One, Other];
测试下 MergeValues:
图片
这样,我们就实现了整个高级类型,整体测试下:
图片
这个案例综合运用到了递归、模式匹配、构造的套路,还是比较复杂的。
可以对照着这张图来看下完整代码:
图片
type ParseParam =
Param extends `${infer Key}=${infer Value}`
? {
[K in Key]: Value
} : {};
type MergeValues =
One extends Other
? One
: Other extends unknown[]
? [One, ...Other]
: [One, Other];
type MergeParams<
OneParam extends object,
OtherParam extends object
> = {
[Key in keyof OneParam | keyof OtherParam]:
Key extends keyof OneParam
? Key extends keyof OtherParam
? MergeValues
: OneParam[Key]
: Key extends keyof OtherParam
? OtherParam[Key]
: never
}
type ParseQueryString =
Str extends `${infer Param}&${infer Rest}`
? MergeParams, ParseQueryString>
: ParseParam;
type ParseQueryStringResult = ParseQueryString<"a=1&a=2&b=2&c=3">;
总结
我们首先复习了下 3 种类型体操的套路:
模式匹配:一个类型匹配一个模式类型,提取其中的部分类型到 infer 声明的局部变量中
构造:通过映射类型的语法来构造新的索引类型,构造过程中可以对索引和值做一些修改
递归:当处理数量不确定的类型时,可以每次只处理一个,剩下的递归来做
然后用这些套路来实现了一个 ParseQueryString 的复杂高级类型。
如果能独立实现这个高级类型,说明你对这三种类型体操的套路掌握的就挺不错的了。
华为南非总经理已在南直接创造超800个就业岗位,间接创造7万多个就业岗位中国驻南非大使馆网站4月14日消息,4月14日,由南非中国经贸协会举办的2022年中资企业招聘大会在约翰内斯堡成功举行。驻南非大使陈晓东应邀出席并致辞,南非总统特别代表就业和劳动部
微信出手!这类行为,严厉打击近日,微信安全中心发布关于治理微信个人账号恶意营销行为的公告,全文如下一直以来,微信始终保持对违法违规行为严厉打击的态度,努力为用户营造一个安全绿色的使用环境。近期,通过用户投诉,
燃油时代的日系霸主,砸2500亿转型电动车在席卷全球的电动化浪潮中,日系车企本是最不积极的一方。固守氢能路线,在电动化转型上投入的迟疑,让日系车企无论是技术还是销量,都远逊于其他电动车厂商。如今,随着特斯拉的全球爆火,新能
不再苦等充电桩,增程式电动汽车打破续航焦虑清明假期刚刚过去不久,选择自驾出行的各位,有没有碰到被困高速的新能源车主?网上一段关于清明节高速充电站的视频上,可以看到等着充电的车辆排着长长的队伍,一眼看不到头。即使没有,但凡关
小鹏汽车CEO何小鹏称,5月份国内车企或全部停产?日前,笔者从相关渠道了解到,小鹏汽车CEO何小鹏称,如果上海和周边的供应链企业还无法找到动态复工复产的方式,五月份可能中国所有的整车厂都要停工停产了。目前蔚来汽车已经宣布停工,并且
新能源汽车补贴退坡是什么意思新能源汽车补贴退坡的意思是在提供补贴的同时,根据新能源汽车发展,有计划有明确目标的逐步减少补贴,和早期的扶上马,送一程的说法比较起来,有明确的时间节点和额度限制。进入2015年,我
计算机行业动态国产EDA有望加速发展据彭博社,美国EDA(Electronicdesignautomation,电子设计自动化)软件公司新思科技(SNPSUS)因涉嫌向受到制裁的中国公司转让关键技术正在接受美国商务部
有哪些石破天惊的神级歌词?看了好几位的回答真的是失望至极,大师级别的作词作曲居然一个都没有被提到,没办法理解石破惊天是个什么意思,不过说起歌词这回事例举几位大师级别的人物第一位江湖词黄霑,这哥们绝对词作者里
高管大震荡,阿里云四面楚歌作者童思思编辑胡展嘉出品零态LT(IDLingTaiLT)内部确实没有对这次事件(阿里云高管变动)的口径,官方没有公开任何信息。关于这次高管变动消息,阿里云内部人士这样告诉零态LT
第八天Python的re库文本操作,如今是最常使用的功能。re是Python内置的库。通过re和正则表达式,我们可以查找,替换字符串。match对象re库有一个常用对象,match。很多re函数会返回它。先
德国或提前取消插电式混动车补贴来源盖世汽车星云据外媒报道,据一位知情人士透露,德国经济部希望在今年年底提前结束针对插电式混合动力汽车的补贴,并从2023年起,将针对电动汽车的现金补贴减少三分之一。这位不愿透露身