持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第30天,点击查看活动详情
1. 引言
接着上一节中,接下来我们继续Ts中等篇的题型练习
https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md 提供的TypeScript 类型体操姿势合集题型,目的是为了让大家更好的了解TS的类型系统,编写自己的类型工具,或者单纯的享受挑战的乐趣!
2. 题型
- String to Union:实现一个将接收到的String参数转换为一个字母Union的类型。
type Test = '123';
type Result = StringToUnion<Test>; // expected to be "1" | "2" | "3"
思路: 首先解析题目,传入一个string类型变量,返回形参成员属性组合而成的联合类型。通过模板字面量类型和infer关键字拆分形参参数第一个成员值,之后配合递归操作获取后面成员属性,在通过联合类型操作合并类型,返回所有成员的联合类型。 解答:
type StringToUnion<T extends string> = T extends `${infer M}${infer N}` ? `${M | StringToUnion<N>}` : never
type Demo = StringToUnion<''> // type Demo = never
type Demo2 = StringToUnion<'t'> // type Demo2 = "t"
type Demo3 = StringToUnion<'hello'> // type Demo3 = "h" | "e" | "l" | "o"
type Demo4 = StringToUnion<'coronavirus'> // type Demo4 = "o" | "c" | "r" | "n" | "a" | "v" | "i" | "u" | "s"
- Merge:将两个类型合并成一个类型,第二个类型的键会覆盖第一个类型的键。
type foo = {
name: string;
age: string;
}
type coo = {
age: number;
sex: string
}
type Result = Merge<foo,coo>; // expected to be {name: string, age: number, sex: string}
思路: 首先合并类型第一要想到的就是映射类型操作符,其次要注意该题目第二个类型的键会覆盖第一个类型的键 的要求,说明在使用映射类型操作的时候,形参二的回抛参数优先与形参一,通过联合类型操作及extends条件判读即可类型合并。 解答:
type Merge<F, S> = {
[P in keyof F | keyof S]: P extends keyof S ? S[P] : P extends keyof F ? F[P] : never
}
type Foo = {
a: number
b: string
}
type Bar = {
b: number
c: boolean
}
type Demo = Merge<Foo, Bar> // type Demo = {a: number;b: number;c: boolean;}
- KebabCase
FooBarBaz -> foo-bar-bazsymbol
思路:
首先KebabCase 接受两个形参,分别是被检测字段及控制是否在字段内部新增'-'形参。观察被检字段,第一步:通过 ${infer F}${infer Rest} 过滤空字符串;第二步:通过**Uppercase extends Lowercase过滤异性符号;第三步抽离当前字段判断是否为大写后,是:改为小写,否:返回原字符串;后续执行递归操作时第二参数形参传入true值,在第二步中执行false语句的前置判断中`${Uppercase extends F ? IsR extends true ? '-' : '' : ''}**给驼峰参数改为小写的同时,加上‘-’字符串。
解答:
type KebabCase<S extends string, IsR = false> =
S extends `${infer F}${infer Rest}`
? Uppercase<F> extends Lowercase<F> ?
`${F}${KebabCase<Rest, true>}`
: `${Uppercase<F> extends F ? IsR extends true ? '-' : '' : ''}${Uppercase<F> extends F ? Lowercase<F> : F}${KebabCase<Rest, true>}`
: S;
type Demo = KebabCase<'FooBarBaz'> // type Demo = "foo-bar-baz"
type Demo2 = KebabCase<'fooBarBaz'> // type Demo3 = "foo-bar"
type Demo3 = KebabCase<'foo-bar'> // type Demo3 = "foo-bar"
type Demo4 = KebabCase<'foo_bar'> // type Demo4 = "foo_bar"
type Demo5 = KebabCase<'Foo-Bar'> // type Demo5 = "foo--bar"
type Demo6 = KebabCase<'-'> // type Demo6 = "-"
type Demo7 = KebabCase<''> // type Demo7 = ""sz900cxxxxxx