当前位置: 首页 > Web前端 > JavaScript

精读《ObjectEntries, Shift, Reverse...》

时间:2023-03-27 14:14:23 JavaScript

解决TS题最好的方法就是多练习。这次解读类型挑战中等难度是41~48题。精读ObjectEntries实现TS版本的Object.entries:interfaceModel{name:string;年龄:数字;位置:字符串[]|null;}typemodelEntries=ObjectEntries//['名称',字符串]|['年龄',数字]|['位置',字符串[]|无效的];经过前面的铺垫,大家应该对TS思维和思维问题都不陌生了。看到这道题后,首先想到的应该是:如何将对象转成Union类型?这个问题不解决,就无从下手。将对象或数组转换为联合类型的思路类似。联合类型的数组使用[number]作为下标:['1','2','3']['number']//'1'|'2'的方法|'3'对象是以[keyofT]为下标:typeObjectToUnion=T[keyofT]再观察这道题,union类型的每一项都是一个数组,分别是Key和Value,这样写起来比较容易,我们只需要构造一个符合Value结构的对象:typeObjectEntries={[KinkeyofT]:[K,T[K]]}[keyofT]for通过单测ObjectEntries<{key?:undefined}>,这样Key位置就不会出现undefined,需要强制对象描述为非可选Key:typeObjectEntries={[KinkeyofT]-?:[K,T[K]]}[keyofT]为了通过单测ObjectEntries>,Value中的undefined必须去掉://本题答案类型RemoveUndefined=[T]扩展[undefined]?T:ExcludetypeObjectEntries={[KinkeyofT]-?:[K,RemoveUndefined]}[keyofT]Shift实现Array.shift的TS版本:类型Result=Shift<[3,2,1]>//[2,1]这道题应该有难有难,直接舍弃第一项,用infer轻松实现://本题答案类型Shift=Textends[inferFirst,...inferRest]?休息:neverTupletoNestedObject实现TupleToNestedObject,其中T只接受字符串数组,P为任意类型,生成满足如下结果的递归对象结构:typea=TupleToNestedObject<['a'],string>//{a:string}typeb=TupleToNestedObject<['a','b'],number>//{a:{b:number}}typec=TupleToNestedObject<[],boolean>//布尔值。如果tuple为空,就返回U类型这道题用到5个知识点:递归,辅助类型,infer,如何指定objectKey,PropertyKey,你要全部知道并结合起来才能解决这道题。首先,因为返回值是一个递归对象,在递归过程中必须不断修改,所以在泛型中加入第三个参数R存放这个对象,递归数组的时候从最后一个开始,使得它从最里面的对象开始一点点“包装”它:typeTupleToNestedObject=/**伪代码Textends[...inferRest,inferLast]*/下一步是如何描述一个对象键?我们在前面的ChainableOptions例子中学习了Q中的K,但是需要注意直接写这个会报错,因为QextendsPropertyKey必须声明。最后处理递归的结束条件,即当T变成空数组时直接返回R://本题答案typeTupleToNestedObject=Textends[]?R:(Textends[...inferRest,inferLastextendsPropertyKey]?(TupleToNestedObject):never)Reverse实现Array.reverse的TS版本:键入a=Reverse<['a','b']>//['b','a']typeb=Reverse<['a','b','c']>//['c','b','a']本题比上一题简单,只需要用到递归://本题答案类型Reverse=Textends[...inferRest,推断完]?[End,...Reverse]:TFlipArguments实现FlipArguments来反转函数T的参数:typeFlipped=FlipArguments<(arg0:string,arg1:number,arg2:boolean)=>void>//(arg0:boolean,arg1:number,arg2:string)=>void这道题和上一道题类似,只是反向内容从数组变成了函数参数。只需使用infer定义函数参数,使用Reverse函数将其反转即可://本题答案类型Reverse=Textends[...inferRest,inferEnd]?[End,...Reverse]:TtypeFlipArguments=Textends(...args:推断Args)=>推断结果?(...args:Reverse)=>Result:neverFlattenDepth实现指定深度的Flatten:typea=FlattenDepth<[1,2,[3,4],[[[5]]]],2>//[1、2、3、4、[5]]。flattern2timestypeb=FlattenDepth<[1,2,[3,4],[[[5]]]]>//[1,2,3,4,[[5]]].Depth默认为1这道题比前面的Flatten难,因为需要控制flatten的次数。基本思路是将Deeptimes展平,所以需要实现一次展平的功能,然后根据Deep值递归对应times:typeFlattenOnce=Textends[inferX,...inferY]?(Xextendsany[]?FlattenOnce:FlattenOnce):U然后实现主函数FlattenDepth,因为TS不能实现+、-符号操作,必须要用数组长度判断和操作数组来辅助实现://FlattenOncetypeFlattenDepth=P['长度']延伸U?T:(FlattenDepth,U,[...P,any]>)当递归没有到达深度U时,用[...P,any]填充一个数组元素,如果可以的话下一次匹配P['length']extendsU,表示已经达到递归深度。但是考虑到测试用例FlattenDepth<[1,[2,[3,[4,[5]]]]],19260817>会造成非常长的递归次数,需要提前终止,即如果展平后已经展平了,就不需要继续递归了。这时可以用FlattenOnceextendsT来判断://本题答案//FlattenOncetypeFlattenDepth=P['length']延伸U?T:(FlattenOnceextendsT?T:(FlattenDepth,U,[...P,any]>))BEM样式字符串实现BEM函数以完成其规则连接:Expect,'btn--small'|'btn--中等'|'btn--large'>>,之前我们学习过如何通过下标将数组或对象转为联合类型,这里还有一个特例,即字符串中这样声明的每一项都会自动进行笛卡尔积进入一个新的联合类型:typeBEM=`${B}__${E[number]}--${M[number]}`This是最简单的写法,但是没有考虑到item的缺失。最好创建一个SafeUnion函数,当传入值不存在时返回空字符串以确保安全跳过:typeIsNever=TValue[]extendsnever[]?true:false;typeSafeUnion=IsNeverextendstrue?“”:联合会;最终代码://这个问题的答案//IsNever,SafeUniontypeBEM=`${B}${SafeUnion<`__${E[number]}`>}${SafeUnion<`--${M[number]}`>}`InorderTraversal实现TS版二叉树中序遍历:consttree1={val:1,left:null,right:{val:2,left:{val:3,left:null,right:null,},right:null,},}asconsttypeA=InorderTraversal//[1,3,2]先回忆一下JS版的实现二叉树的中序遍历:functioninorderTraversal(tree){if(!tree)return[]return[...inorderTraversal(tree.left),res.push(val),...inorderTraversal(tree.right)]}对于TS来说,实现递归的方式有点不同,就是通过扩展TreeNode判断它不为Null然后递归://本题答案interfaceTreeNode{val:numberleft:TreeNode|null右:TreeNode|空}t类型InorderTraversal=[T]扩展[TreeNode]?([...InorderTraversal,T['val'],...InorderTraversal]):[]你可能会问,为什么不能用null像JS一样进行判断?类型InorderTraversal=[T]扩展[null]?[]:([//error...InorderTraversal,T['val'],...InorderTraversal])如果你这样写,你会发现TS抛出异常,因为此时TS无法判断T是否符合TreeNode类型,所以一般在执行操作时使用肯定判断。总结这几类挑战题需要灵活组合TS的基础知识才能破解。常用的有:如何操作对象,增减Key,只读,合并为一个对象等,递归,辅助类型。推断知识点。联合类型,如何从对象或数组生成联合类型,字符串模板和联合类型之间的关系。讨论地址为:Jingdu《ObjectEntries, Shift, Reverse...》·Issue#431·dt-fe/weekly想参与讨论的请戳这里,每周都有新话题,周末或周一发布。前端精读——帮你过滤靠谱的内容。关注前端精读微信公众号版权声明:免费转载-非商业-非衍生保留属性(CreativeCommons3.0License)