当前位置: 首页 > 科技观察

TS 类型体操:图解一个复杂高级类型

时间:2023-03-14 23:18:24 科技观察

TS类型体操:复杂高级类型图Recursion等套路对提高类型编程水平很有帮助。我们要实现的高级类型如下:其类型参数为参数字符串查询字符串,将返回解析后的参数对象。如果有同名的参数,值会被合并。先不急着去实现,先回顾一下类型体操的相关基础知识:基本类型体操模式匹配模式匹配是指将一个模式类型与一个类型进行匹配,将其中的一些类型提取到infer声明的局部变量中。比如提取a=b中的a和b:这个模式匹配例程在数组、字符串、函数等类型中有很多应用。详细内容可以阅读之前的文章:模式匹配——让你的ts类型体操水平提升的套路构造映射类型。映射类型用于生成索引类型。在生成过程中,可以对索引或索引值进行一些修改。比如指定key和value生成一个索引类型:详细可以参考之前的一篇文章:TS类型体操:索引类型映射与映射递归TypeScript高级类型支持递归,可以处理不确定数的问题。比如不确定长度的字符串的反转:typeReverseStr=Strextends`${inferFirst}${inferRest}`?ReverseStr:结果;简单了解模式匹配、构造、递归后,就可以开始实现这个复杂的高级类型ParseQueryString:思维分析假设有这样一个查询字符串:a=1&a=2&b=3&c=4。我们先把它分成4个部分:即a=1,a=2,b=3,c=4。这是通过上述模式匹配提取的。每个部分都可以进一步处理以提取键值并构造索引类型。例如a=1可以通过模式匹配提取a和1,然后构造索引类型{a:1}。所以有4种索引类型{a:1}、{a:2}、{b:3}、{c:4}。最后,将它们合并为一个就足够了。合并的时候,如果有相同的键值,应该放到一个数组中。最终生成的索引类型为:{a:[1,2],b:3,c:4}整体过程是这样的:第一步不知道有多少个a=1,b=2这样的queryparam,所以递归地做模式匹配来提取。这就是这个高级类型的实现思路。记下来:代码实现按上图顺序实现,先提取查询字符串中的每一个查询参数:查询参数个数不确定,所以使用递归:typeParseQueryString=Str扩展`${inferParam}&${inferRest}`?MergeParams,ParseQueryString>:ParseParam;类型参数Str是要处理的查询字符串。通过模式匹配将第一个queryparam提取到infer声明的局部变量Param中,其余字符串放入Rest中。使用ParseParam对Param进行处理,递归处理剩下的,最后合并在一起,就是MergeParams。如果模式匹配不满足,说明还剩下最后一个queryparam,同样被ParseParam处理。然后实现每个queryparam的parse:这个就是使用模式匹配来提取key和value,然后构造一个索引类型:typeParseParam=Paramextends`${inferKey}=${inferValue}`?{[KinKey]:Value}:{};这里,映射类型的语法用于构造索引类型。让我们先测试一下这个ParseParam:在解析每个查询参数之后,将它们合并在一起:合并的部分是MergeParams:typeMergeParams={[KeyinkeyofOneParam|keyofOtherParam]:KeyextendskeyofOneParam?Key扩展了keyofOtherParam?MergeValues:OneParam[Key]:KeyextendskeyofOtherParam?OtherParam[Key]:never}两种索引类型的合并还需要用映射类型的语法构造一个新的索引类型。key取自两者,即keyinkeyofOneParam|其他参数的键。value有两种情况:如果两种索引类型都有key,则需要合并,即MergeValues。如果只有一种索引类型,则取其值,即OtherParam[key]或OneParam[Key]。合并的时候,如果两者相同,返回任意一个,如果不相同,则合并成一个数组返回,即[One,Other]。如果它本来是一个数组,它就是数组[One,...Other]的合并。输入MergeValues=OneextendsOther?一:Otherextendsunknown[]?[一个,...其他]:[一个,其他];测试MergeValues:这样我们就实现了整个进阶类型,整体测试下:这个案例综合使用了递归、模式抽取、构造的套路,还是比较复杂的。可以根据这张图来看下完整代码:typeParseParam=Paramextends`${inferKey}=${inferValue}`?{[KinKey]:Value}:{};typeMergeValues=OneextendsOther?一:Otherextendsunknown[]?[一个,...其他]:[一个,其他];键入MergeParams={[KeyofOneParam|keyofOtherParam]:KeyextendskeyofOneParam?Key扩展了keyofOtherParam?MergeValues:OneParam[Key]:KeyextendskeyofOtherParam?OtherParam[Key]:never}typeParseQueryString=Strextends`${inferParam}&${inferRest}`?MergeParams,ParseQueryString>:ParseParam;类型ParseQueryStringResult=ParseQuerySt环<'a=1&a=2&b=2&c=3'>;总结我们先回顾了下三种类型体操的套路:模式匹配:一个类型匹配一个模式类型,将部分类型提取到infer声明的局部变量中构造:通过语法构造一个新的索引类型映射类型,并且在构建过程中可以对索引和值进行一些修改使用这些例程来实现一个复杂的高级类型ParseQueryString。如果你能独立完成这一进阶式,就说明你已经很好地掌握了这三种体操套路。