TS 类型体操 之 字符串的妙用
这里记录一下做题过程中遇到的一些字符串处理比较巧妙的技巧,后面主要引入的题目是 00529-medium-absolute
对于字符串的用法,前置知识的篇章已经介绍过了,例子如下。理解了这部分例子后相信可以解决很多的题目了
type testInfer<T extends string> = T extends `${infer F}${infer S}${infer R}` ? [F, S, R] : T
type testInfer1 = testInfer<'123456'>
// 按照占位符的特性,前面F和S分别占据2个字符,剩余的都给R占去了
// type testInfer1 = ["1", "2", "3456"]
// 稍作改动,在S占位符后面添加一个5
type testInfer2<T extends string> = T extends `${infer F}${infer S}5${infer R}` ? [F, S, R] : T
type testInfer3 = testInfer<'123456'>
// F 占第一个字符 = 1
// S 占据2-4,因为在R之前有一个5,所以S代表了第二个字符开始到5的所有字符
// 那么R就是从5开始,到末尾,所以得出的结果如下:
// type testInfer1 = ["1", "234", "6"]
00529-medium-absolute 题目详解
需求:实现一个接收 string,number 或 bigInt 类型参数的 Absolute 类型,返回一个正数字符串。
- 接收 string,number,或者 bigInt
- 返回正整数
- 返回字符串
挑几个代表性的测试用例
type testcase = Absolute<0>
type testcase = Absolute<-5>
type testcase = Absolute<'0'>
type testcase = Absolute<'-0'>
type testcase = Absolute<'10'>
type testcase = Absolute<-1_000_000n>
type testcase = Absolute<9_999n>
解题思路
思路 1: 比较绕的思路
- 把数字都先转换为字符串
- 逐个字符串比较(使用 infer 提取每个字符串,然后比较,比较成功后存储到一个变量 R 中)
- 当传入的字符串为空后返回变量 R
思路 1 实现:
type NumberStr = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
type Absolute<T extends number | string | bigint, R extends string = ''> = `${T}` extends `${infer F}${infer Rest}`
? F extends NumberStr
? Absolute<Rest, `${R}${F}`>
: Absolute<Rest, R>
: R
其中,当传入的泛型 T 可能是 number 或者 bigInt 类型的时候,无法直接用 extends xxx
所以一开始的技巧就是 ${T}
把不管是不是字符串类型的,都转换为字符串(这也是因为数字类型可以转字符串)
剩下的就是逐个字符比较。
思路 2: 利用数字特性,比如 1_000_000n 在程序 tostring 的时候其实会自动转换为 1000000,并不用我们考虑太多去除 \_
或者 去除n
的逻辑
思路 2 实现:
type Absolute<T extends number | string | bigint> = `${T}` extends `-${infer Num}` ? Num : `${T}`
这种方法直接匹配传入的内容是不是带有 -
号
- 没有的话,说明是正整数(有可能是数字)所以包裹一层`` 直接当作字符串输出
- 有
-
号的话,利用 infer 和 字符串的特性,排除第一个-,剩下的就都是对应数字的字符串了
小结
- 在匹配过程中,可以使用
${T}
的语法,把 number 也转换为字符串 - 数字类型,包括 bigInt 类型转换的时候其实会自动转换为数字,利用该特点还能少写点代码