typescript类型体操--驼峰下划线互转
需求
1.对于给定下划线形式的字符串类型T,实现一个泛型CamelCase
,返回驼峰形式的类型G。
2.对于给定驼峰形式的字符串类型G,实现一个泛型UnderlineCase
,返回下划线形式的类型T。
type camelCaseResult = CamelCase<'hello_my_love'> // expected to 'helloMyLove'
type UnderlineCaseResult =
UnderlineCase<'helloMyLove'> // expected to 'hello_my_love'
前置知识
分析
CamelCase
对于下划线转小驼峰,我们实际需要转换的字符串中可能的单词个数(以_
分隔)是不定的,为此,我们该操作会涉及到递归,递归终止条件为剩余子串是否含有_
。
使用extends
做类型约束时,我们可以结合ts类型推断中使用模版字符串加infer
关键字指定局部变量。
在我的观察中,推断时,除非指定非字母的分隔符,否则推断中每次匹配都将把字符串按单个字母拆分,以下就是一个例子:
type ITest<Str extends string> = Str extends `${infer A}_${infer B}${infer C}`
? `A-(${A})/B-(${B})/C-(${C})` : Str
于是我们extends
约束的类型为
`${infer First}_${infer Second}${infer Rest}`
以'hello_my_love'为例,首次匹配时:
First -- 'hello';
Second -- 'm'
Rest -- "y_love"
显而易见地,hello
不需要处理,m
需要转为M
,y_love
则进入到下一次匹配中(递归操作)。
第二次匹配时:
First -- 'y';
Second -- 'l'
Rest -- "ove"
因此,CamelCase
这个泛型为:
type CamelCase<Str extends string> =
Str extends `${infer First}_${infer Second}${infer Rest}`
? `${First}${Uppercase<Second>}${CamelCase<Rest>}`
: Str
UnderlineCase
易知,关键是识别出helloMyLove
中的M
和L
,但ts的类型推断中似乎并没有已存在的类型判断某个字母是否是大写字母,只好手写了:
type UpperLetter = 'A'|'B'|'C'
|'D'|'E'|'F'|'G'|'H'|'I'|'J'|'K'|'L'|'M'|'N'|'O'|'P'
|'Q'|'R'|'S'|'T'|'U'|'V'|'W'|'X'|'Y'|'Z'
按照Camelcase
中的思路,约束类型可以为:
`${infer First}${infer Upper}${infer Rest}`
第一次匹配时:
First -- 'h'
Upper -- 'e'
Rest -- 'lloMyLove'
第二次匹配时:
First -- 'l'
Upper -- 'l'
Rest -- 'oMyLove'
第三次匹配时:
First -- 'o'
Upper -- 'M'
Rest -- 'yLove'
...
我们应该做的应该是把大写字母M
和L
分别转为_m
和_l
,因此,新建一个类型UnderlineChar
实现:
type UnderlineChar<Str extends string> =
Str extends UpperLetter
? `_${Lowercase<Str>}`
: Str
最终的结果为:
type UnderlineCase<Str extends string> =
Str extends `${infer First}${infer Upper}${infer Rest}`
? `${UnderlineChar<First>}${UnderlineChar<Upper>}${UnderlineCase<Rest>}`
: Str
应用场景
CamelCase
function toCamelString<T extends string,>(str:T):CamelCase<T>
function toCamelString(str){
return str.replace(/_(\w)/g, function(_, letter){
return letter.toUpperCase();
});
}
UnderlineCase
function toUnderlineString<T extends string>(str:T):UnderlineCase<T>
function toUnderlineString(str:string){
return str.replace(/([A-Z])/g,function (_,letter){
return '_'+letter.toLowerCase()
})
}
转载自:https://juejin.cn/post/7337354931480444968