持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
前言
在学习typescript的过程当中,有一个github库对其类型的学习特别有帮助,是一个有点类似于leetcode的刷题项目,能够在里面刷各种关于typescript类型的题目,在之前篇文章中,我们完成了中等的第二十一题,今天来做中等的第二十二题 531-medium-string-to-union
下面这个是类型体操github仓库:
531-medium-string-to-union
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<StringToUnion<''>, never>>,
Expect<Equal<StringToUnion<'t'>, 't'>>,
Expect<Equal<StringToUnion<'hello'>, 'h' | 'e' | 'l' | 'l' | 'o'>>,
Expect<Equal<StringToUnion<'coronavirus'>, 'c' | 'o' | 'r' | 'o' | 'n' | 'a' | 'v' | 'i' | 'r' | 'u' | 's'>>,
]
从README和测试用例中能够得出,我们需要实现一个工具函数 StringToUnion 能够将字符串转化为联合类型。
利用 JS 进行模拟学习
由于JS中不存在联合类型的概念,我们用数组来进行代替,将一个字符串进行单个分割,并且放入一个数组中返回,值得注意的是,当字符串为空的时候,需要返回 never
function stringToUnion(str:string){
let arr: any[] = []
while(str) {
arr.push(str[0])
str = str.slice(1,str.length)
}
if(arr.length==0) {
return 'never'
}else {
return arr
}
}
实现 StringToUnion
那么 TS 根据 JS 的逻辑进行处理,首先我们需要一个参数用来保存最后需要的联合类型,所以需要在入参中定义一个默认的参数,类型为string,用来保存每个字符组成的联合类型:
type StringToUnion<T extends string,U extends string=''> = any
接着就是需要对字符串进行处理,判断字符串是否能够进行分割,可以的话就使用模板字面量获取首个字符和剩余字符,并且将剩下字符作为第一个参数,U和首个字符的联合类型作为第二个参数,递归回 StringToUnion。
type StringToUnion<T extends string,U extends string=''> = T extends `${infer S}${infer R}`
? StringToUnion<R,U | `${S}`>
: U
然后就会发现,一开始的 U 是一个空字符串,所以这样写的话,会把这个空字符串也一并并入最后的联合类型。
所以我们需要对 U 进行初始值判断,刚开始的第一次递归,U 不应该被联合进第二个参数:
type StringToUnion<T extends string,U extends string=''> = T extends `${infer S}${infer R}`
? U extends ''
? StringToUnion<R,`${S}`>
: StringToUnion<R,U | `${S}`>
: U
然后就是剩余一种特殊情况还未考虑,就是当输入的字符串是空字符串的时候,需要返回 never,所以我们对最后的答案进行判断,要是为空字符串的话,那就说明一开始输入的是空字符串,返回 never,不然就返回 U。
type StringToUnion<T extends string,U extends string=''> = T extends `${infer S}${infer R}`
? U extends ''
? StringToUnion<R,`${S}`>
: StringToUnion<R,U | `${S}`>
: U extends ''
? never
: U
这样测试用例就能够全部通过了。
知识点
关于上述提到了部分的知识点:
- 模板字面量
- 条件链
今天的题目没有新的知识点,主要是需要灵活运用入参定义参数和条件链之间的配合,来合理的构建我们需要的答案。
总结
今天我们做完了中等的第二十二题,题目属于比较常规的问题,和最近常见的题型非常的相似,主要都是通过定义参数以及条件链来进行判断以及特殊处理。