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

使用了模板字面量类型,同事都说太强了!

时间:2023-03-13 06:03:31 科技观察

你听说过模板字面量类型吗?你想知道如何使用模板文字类型来减少TypeScript项目中的代码重复吗?如果你愿意,看完本文的内容,或许你就会明白了。假设我们要定义一个类型来描述CSS填充规则。如果您了解TypeScript类型别名和联合类型,则可以轻松定义CssPadding类型。输入CssPadding=|“填充左”|“填充右”|“填充顶部”|“填充底部”;但是如果我们要继续定义一个新的类型来描述CSS边距规则,你是不是马上就会把它想象成定义CssPadding类型一样的方式。输入MarginPadding=|“左边距”|“右边距”|“保证金顶部”|“底边距”;对于上面定义的两种类型,虽然可以满足我们的需求。但是在定义这两种类型的过程中还是存在一些重复的代码。那么如何解决这个问题呢?这时候,我们可以使用TypeScript4.1引入一个新的模板字面量类型。具体用法如下:typeDirection="left"|“正确”|“顶部”|“底部”;键入CssPadding=`padding-${Direction}`;键入MarginPadding=`margin-${Direction}`;看完上面的代码,是不是觉得简单多了。类似于JavaScript中的模板字符串,模板字面量类型用反引号括起来,可以包含${T}形式的占位符,其中类型变量T的类型可以是string、number、boolean或bigint类型。模板字面量类型不仅为我们提供了拼接字符串字面量的能力,还可以将非字符串基本类型字面量转换为对应的字符串字面量类型。让我们举一些具体的例子:typeEventName=`${T}Changed`;typeConcat=`${S1}-${S2}`;类型ToString=`${T}`;类型T0=EventName<"foo">;//'fooChanged'typeT1=Concat<"Hello","World">;//'Hello-World'typeT2=ToString<"Aboge"|第666章真|-1234n>;//"阿宝哥"|“真实”|“666”|上面例子的“-1234”话虽这么说,但实际上并没有那么复杂。但现在问题来了,如果传入EventName或Concat实用程序类型的实际类型是联合类型,会发生什么情况?接下来,让我们验证一下:typeT3=EventName<"foo"|“酒吧”|“巴兹”>;//"fooChanged"|“酒吧改变”|“bazChanged”类型T4=Concat<“top”|“底部”,“左侧”|"right">;//为什么是"top-left"|“右上角”|“左下角”|“右下角”生成这样的类型?这是因为对于模板字面量类型,当类型占位符的实际类型为联合类型(A|B|C)时,会自动展开:`[${A|B|C}]`=>`[${A}]`|`[${B}]`|`[${C}]`以及包含多个类型占位符的情况,例如Concat工具类型。多个占位符中的联合类型解析为叉积:`${A|B}-${C|D}`=>`${A}-${C}`|`${A}-${D}`|`${B}-${C}`|`${B}-${D}`理解了上面的运算规则后,你应该能够理解生成的T3和T4类型。在使用模板字面量类型的过程中,我们还可以使用TypeScript自带的处理字符串类型的工具类型,如Uppercase、Lowercase、Capitalize、Uncapitalize。具体用法如下:typeGetterName=`get${Capitalize}`;typeCases=`${Uppercase}${Lowercase}${Capitalize}${Uncapitalize}`;typeT5=GetterName<'foo'>;//"getFoo"typeT6=Cases<'bar'>;//"BARbarBarbar"其实,模板字面量类型的能力是很强大的,结合TypeScript的条件类型和infer关键字,我们也可以实现类型推断。类型方向=“左”|“正确”|“顶部”|"bottom";typeInferRoot=Textends`${inferR}${Capitalize}`?R:T;typeT7=InferRoot<"marginRight">;//“保证金”类型T8=InferRoot<"paddingLeft">;//"padding"在上面的代码中,InferRoot工具类型使用了TypeScript条件类型并进行推断。如果这两个知识点还不明白,可以看看《使用TS条件类型,同事叫YYDS》和《学TS推断,写泛型真香!》这两篇文章。此外,TypeScript4.1允许我们使用as子句重新映射映射类型中的键。它的语法如下:typeMappedTypeWithNewKeys={[KinkeyofTasNewKeyType]:T[K]//^^^^^^^^^^^^^//这是新语法!}其中NewKeyType的类型必须是字符串|的子类型编号|符号联合类型。在重映射的过程中,结合模板字面量类型提供的能力,我们可以实现一些有用的实用类型。例如,我们可以定义一个Getters工具类型,为对象类型生成对应的Getter类型:typeGetters={[KinkeyofTas`get${Capitalize}`]:()=>T[K]};接口人{名称:字符串;年龄:数字;location:string;}typeLazyPerson=Getters;//{//getName:()=>string;//getAge:()=>number;//getLocation:()=>string;//}在上面的代码,因为keyofT返回的类型可能包含符号类型,而Capitalize工具类型需要的类型需要是字符串类型的子类型,所以需要通过交集运算符进行类型过滤。除了实现简单的工具类型,我们还可以实现更复杂的工具类型。例如,用于获取对象类型中任意一个级别属性的类型。输入PropType=stringextendsPath?未知:路径扩展keyofT?T[Path]:Pathextends`${inferK}.${inferR}`?K扩展了T的键?PropType:unknown:unknown;声明函数getPropValue(obj:T,path:P):PropType;constobj={a:{b:{c:666,d:"阿宝哥"}}};leta=getPropValue(obj,"a");//{b:{c:number,d:string}}letab=getPropValue(obj,"a.b");//{c:数字,d:字符串}letabd=getPropValue(obj,"a.b.d");//string上述代码中,PropType工具类型涉及到TypeScript中的多个核心知识点。