持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情
前言
在学习typescript的过程当中,有一个github库对其类型的学习特别有帮助,是一个有点类似于leetcode的刷题项目,能够在里面刷各种关于typescript类型的题目,在上一篇文章中,我们完成了中等的第十二题,今天来做中等的第十三题 110-medium-capitalize
下面这个是类型体操github仓库:
110-medium-capitalize
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyCapitalize<'foobar'>, 'Foobar'>>,
Expect<Equal<MyCapitalize<'FOOBAR'>, 'FOOBAR'>>,
Expect<Equal<MyCapitalize<'foo bar'>, 'Foo bar'>>,
Expect<Equal<MyCapitalize<''>, ''>>,
Expect<Equal<MyCapitalize<'a'>, 'A'>>,
Expect<Equal<MyCapitalize<'b'>, 'B'>>,
Expect<Equal<MyCapitalize<'c'>, 'C'>>,
Expect<Equal<MyCapitalize<'d'>, 'D'>>,
Expect<Equal<MyCapitalize<'e'>, 'E'>>,
Expect<Equal<MyCapitalize<'f'>, 'F'>>,
Expect<Equal<MyCapitalize<'g'>, 'G'>>,
Expect<Equal<MyCapitalize<'h'>, 'H'>>,
Expect<Equal<MyCapitalize<'i'>, 'I'>>,
Expect<Equal<MyCapitalize<'j'>, 'J'>>,
Expect<Equal<MyCapitalize<'k'>, 'K'>>,
Expect<Equal<MyCapitalize<'l'>, 'L'>>,
Expect<Equal<MyCapitalize<'m'>, 'M'>>,
Expect<Equal<MyCapitalize<'n'>, 'N'>>,
Expect<Equal<MyCapitalize<'o'>, 'O'>>,
Expect<Equal<MyCapitalize<'p'>, 'P'>>,
Expect<Equal<MyCapitalize<'q'>, 'Q'>>,
Expect<Equal<MyCapitalize<'r'>, 'R'>>,
Expect<Equal<MyCapitalize<'s'>, 'S'>>,
Expect<Equal<MyCapitalize<'t'>, 'T'>>,
Expect<Equal<MyCapitalize<'u'>, 'U'>>,
Expect<Equal<MyCapitalize<'v'>, 'V'>>,
Expect<Equal<MyCapitalize<'w'>, 'W'>>,
Expect<Equal<MyCapitalize<'x'>, 'X'>>,
Expect<Equal<MyCapitalize<'y'>, 'Y'>>,
Expect<Equal<MyCapitalize<'z'>, 'Z'>>,
]
从README和测试用例中能够得出,我们需要实现一个工具函数 MyCapitalize 它的作用和 TS 内置的 Capitalize 是完全相同的,能够将字符串字面量的第一个字符变成大写。
通过 JS 对比学习
我们需要实现一个函数,将传入的字符串的首位字母变成大写,通过JS内置的工具应该就能够很容易实现。
function myCapitalize(str:string){
return str[0].toUpperCase() + str.slice(1,str.length)
}
但是有没有考虑过,如果不借助工具,我们需要怎么来实现呢,其实也很简单,因为字母小写转大写的方法也就是列出小写字母的左右情况,然后碰到了就用大写字母进行替换,所以我们只需要加一层映射就能够简单完成。这里 JS 就不写了,我们等一下的 TS 中也会使用这种思路。
实现 MyCapitalize
通过 JS 的实现思路,我们发现,题目十分的简单,只需要拿到字符串的第一个字母然后进行小写转大写就完成了,那么在 JS 中 存在着字符串方法 toUpperCase 来帮助字符串小写转大写,那么在 TS 有没有这种方法呢,答案当然是有的,我们通过 Uppercase 工具类型也能够实现字符串字面量的小写转大写:
type MYCA1 = Uppercase<'asd'>
// type MYCA1 = "ASD"
那么这道题就变得十分的简单,我们只需要单独拿出字符串字面量的第一位来进行转化,然后和剩下的字符串字面量拼接起来就完成了,关于结果的字符串字面量拼接,这个在前几天中也提到过,模板字面量也能够被用在结果当中。
type MYCA2 = 'asd' extends `${infer First}${infer Rest}`
?`${Uppercase<First>}${First}${First}`
:never
// type MYCA2 = "Aaa"
所以我们只需要取到字符串的第一位进行大写转化之后,和剩下的拼接起来:
type MyCapitalize<S extends string> = S extends `${infer F}${infer Rest}`
? `${Uppercase<F>}${Rest}`
: S
要注意到测试用例中存在着会传入空字符的情况,那么我们在false分支中就需要包容这种情况,返回空字符串或者本身都是可以的。
然后就是上面说到的,我们如果不想使用 TS 提供的 Uppercase 工具类型,那么我们应该如何自己定义呢。
其实也很简单,我们只需要列出所有字母的情况,做一个映射表,将所有的小写字母映射为大写字母就可以了。
interface MyUppercase {
a: "A"
b: "B"
c: "C"
d: "D"
e: "E"
f: "F"
g: "G"
h: "H"
i: "I"
j: "J"
k: "K"
l: "L"
m: "M"
n: "N"
o: "O"
p: "P"
q: "Q"
r: "R"
s: "S"
t: "T"
u: "U"
v: "V"
w: "W"
x: "X"
y: "Y"
z: "Z"
}
type MYCA3 = MyUppercase["a"]
// type MYCA3 = "A"
当然这是最简单的实现,只能够进行单个字母的小写想大写转化,但是在这道题中已经足够了。
但是在我们使用这个接口的时候,会发现报错了:
这是因为,你没有办法保证入参F一定是这个接口中存在的属性,所以我们需要为这个F添加约束:
type MyCapitalize<S extends string> = S extends `${infer F extends keyof MyUppercase}${infer Rest}`
? `${MyUppercase[F]}${Rest}`
: S
这样测试就能够全部通过了,以上就是两种不同的解法。
知识点
关于上述提到了部分的知识点:
- 模板字面量
- infer 关键字
- 条件链
- 索引取值
今天的知识点都是之前有提到过了,在这里就不在做过多的描写,不懂得可以去看一下之前的文章或者相关题型。
总结
今天我们做完了中等的第十三题,题型和昨天也是大部分相似,都是需要做字符串字面量进行操作,我们可以通过 TS 提供的内置工具类型,但是要知道,如果让你自己去实现,需要怎么去写这些工具类型。