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

精读《Promise.all, Replace, Type Lookup...》

时间:2023-03-28 16:54:29 HTML

解决TS题最好的方法就是多练习。这次的interpretingtype-challengesMedium的难度是9~16题。精读Promise.all实现PromiseAll函数,输入PromiseLike,输出Promise,其中T为输入分析结果:constpromiseAllTest1=PromiseAll([1,2,3]asconst)constpromiseAllTest2=PromiseAll([1,2,Promise.resolve(3)]asconst)constpromiseAllTest3=PromiseAll([1,2,Promise.resolve(3)])这道题的难点不在于如何处理Promise,而在于{[KinkeyofT]:T[K]}在TS中描述数组也适用,超乎JS玩家的想象://本题答案declarefunctionPromiseAll(values:T):Promise<{[KinkeyofT]:T[K]extendsPromise?U:T[K]}>不知道是bug还是feature,不过TS的{[KinkeyofT]:T[K]}是同时兼容元组、数组和对象类型的。TypeLookup实现LookUp,从联合类型T中查找类型P的项并返回:interfaceCat{type:'cat'breeds:'Abyssinian'|'短毛猫'|'卷曲'|'孟加拉'}接口狗{类型:'狗'品种:'猎犬'|'布列塔尼'|'斗牛犬'|'Boxer'颜色:'棕色'|'白色'|'黑色'}typeMyDog=LookUp//应该是`Dog`这道题比较简单,只要学会灵活使用infer和extends即可://这道题的答案typeLookUp=Textends{type:infer你}?(UextendsP?T:never):never联合类型的判断是一个一个来的,所以我们只需要对每一个单独写一个判断即可。在上面的方案中,我们首先使用extend+infer将T的类型锁定为一个包含typekey的对象,并将inferU指向type,所以我们使用三元运算符来判断UextendsP?在内部匹配类型Types被挑选出来。作者查看了答案,发现还有更高级的解决方法://本题答案typeLookUp=Uextends{type:T}?U:never这个方案更简洁完整:在泛型处使用extends{type:any}和extendsU['type']直接锁定入参类型,这样可以更早的进行错误检查。TextendsU['type']恰恰缩小了参数T的范围,可以了解到之前定义的泛型U可以直接被后面新的泛型使用。Uextends{type:T}是一种新的思维方式。第一个答案我们的思路是“找对象中的type值来判断”,而第二个答案直接用整个对象结构{type:T}来判断,更纯TS思维。TrimLeft实现了TrimLeft,清除字符串左边的空格:typetrimed=TrimLeft<'HelloWorld'>//预期为'HelloWorld'在TS中,递归只能用来处理这样的问题,不能用正则表达式。更容易想到下面的写法://TheanswertothisquestiontypeTrimLeft=Textends`${inferR}`?TrimLeft:T即如果字符串前面有空格,去掉空格继续递归,否则返回字符串本身。掌握这道题的关键在于infer也可以用于字符串内的推导。Trim实现了Trim,并清除字符串左右两边的空格:typetrimmed=Trim<'HelloWorld'>//expectedtobe'HelloWorld'问题的简单解决方法是trim双方://ThisquestionAnswertypeTrim=TrimLeft>typeTrimLeft=Textends`${inferR}`?TrimLeft:TtypeTrimRight=Textends`${inferR}`?TrimRight:这个成本很低,而且性能还不错,因为写TrimLeft和TrimRight很简单。如果不用先左后右的方法,想一次完成,需要一些TS思维。愚蠢的想法是“如果左边有空格就拆分左边,或者如果右边有空格就拆分右边”,最后写出一个复杂的三元表达式。更好的想法是使用TS联合类型://TheanswertothisquestiontypeTrim=Textends`${inferR}`|`${推断R}`?Trim:Textends也可以跟在Union类型之后,这样任何匹配都会转到Trim递归。这就是很难解释清楚的TS思维。没有它,你只能想到三元表达式,但是一旦你理解了union类型,你也可以在extends中使用它。TS帮助你具备了N元表达式的能力,那么写出来的代码会非常优雅。CapitalizeimplementsCapitalize将字符串的首字母大写:typecapitalized=Capitalize<'helloworld'>//expectedtobe'Helloworld'如果这是一道JS题,那么简单,但是题目是TS是的,我们需要再次切换到TS思维。首先要知道如何使用基本函数Uppercase将单个字母转为大写,再配合infer,就不用说了:typeMyCapitalize=Textends`${inferF}${推断你}`?`${Uppercase}${U}`:TReplace实现TS版本函数Replace,将字符串From替换为To:typereplaced=Replace<'typesarefun!','fun','awesome'>//应该是'typesareawesome!'把From放在字符串中间,用两个infers推导,最后的输出不变,把From换成To即可://本题答案typeReplace=Sextends`${inferA}${From}${inferB}`?`${A}${To}${B}`:SReplaceAll实现ReplaceAll,将字符串From替换为To:typereplaced=ReplaceAll<'types','',''>//expectedtobe'types'这道题和上一题的区别在于Replaceall,解法一定是递归,关键是递归时的判断条件是什么。想了想,如果inferfromcanmatch,那不就说明递归还是可以的吗?所以加一层三元判断Fromextends''://本题答案类型ReplaceAll=Sextends`${inferA}${From}${infer乙}`?(Fromextends''?`${A}${To}${B}`:ReplaceAll<`${A}${To}${B}`,From,To>):SAppendArgumentimplementationTypeAppendArgument,将函数参数扩展一个:typeFn=(a:number,b:string)=>numbertypeResult=AppendArgument//expectedbe(a:number,b:string,x:boolean)=>number这道题很简单,就用infer://TheanswertothisquestiontypeAppendArgument=Fextends(...args:inferT)=>inferR?(...args:[...T,E])=>R:F综上所述,这几道题比较简单,主要考察infer和recursion的熟练运用。讨论地址是:Jingdu《Promise.all, Replace, Type Lookup...》·Issue#425·dt-fe/weekly想参与讨论的请戳这里,每周都有新话题,周末或周一发布。前端精读——帮你过滤靠谱的内容。关注前端精读微信公众号版权声明:免费转载-非商业-非衍生保留属性(CreativeCommons3.0License)