持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
1. 引言
接着上一节中,接下来我们继续Ts中等篇的题型练习
https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md 提供的TypeScript 类型体操姿势合集题型,目的是为了让大家更好的了解TS的类型系统,编写自己的类型工具,或者单纯的享受挑战的乐趣!
2. 题型
- Type LookUp:有时,您可能希望根据某个属性在联合类型中查找类型。 在此挑战中,我们想通过在联合类型Cat | Dog中搜索公共type字段来获取相应的类型。换句话说,在以下示例中,我们期望LookUp<Dog | Cat, 'dog'>获得Dog,LookUp<Dog | Cat, 'cat'>获得Cat。
interface Cat {
type: 'cat'
breeds: 'Abyssinian' | 'Shorthair' | 'Curl' | 'Bengal'
}
interface Dog {
type: 'dog'
breeds: 'Hound' | 'Brittany' | 'Bulldog' | 'Boxer'
color: 'brown' | 'white' | 'black'
}
type MyDog = LookUp<Cat | Dog, 'dog'> // expected to be `Dog`
思路: 首先判断第一步要使用的操作符,extends限制T为string类型,U 形参传入后为分布式条件类型判断,依次判断当U 为Cat类型或者Dog类型时候,所属属性type是否相等于传入形参的T值,是的话回抛当前类型U;也许有同学疑惑为什么U extends {type: T} 这样就可以判断我们要寻找的类型,举个例子:当U为Cat 类型,T为‘cat’字符串类型时
type Whether = Cat extends {type: 'cat'} ? true : false // type Whether = true
因为在extends对比语句中,左边Cat 比{type: 'cat'} 更具体(也就是属性更多),是 {type: 'cat'}的子集,所以返回左边的true,这样你就可以理解U extends {type: T} 的作用了吧。 解答:
type LookUp<U, T extends string> = U extends {type: T} ? U : never
interface Cat {
type: 'cat'
breeds: 'Abyssinian' | 'Shorthair' | 'Curl' | 'Bengal'
}
interface Dog {
type: 'dog'
breeds: 'Hound' | 'Brittany' | 'Bulldog' | 'Boxer'
color: 'brown' | 'white' | 'black'
}
type Animal = Cat | Dog
type Demo = LookUp<Animal, 'dog'> // type Demo = Dog
type Demo2 = LookUp<Animal, 'cat'> // type Demo2 = Cat
- Trim:实现Trim,它是一个字符串类型,并返回一个新字符串,其中两端的空白符都已被删除。
type trimed = Trim<' Hello World '> // expected to be 'Hello World'
思路:
使用${}模板自变量语法配合infer 关键字类型在结合extends判断语句结合递归操作就可以推断最后目标类型
解答:
type Trim<S extends string> = S extends `${'\n' | '\t' | ' '}${infer R}` | `${infer R}${'\n' | '\t' | ' '}` ? Trim<R> : S
type Demo = Trim<'str'> // type Demo = "str"
type Demo2 = Trim<' str'> // type Demo2 = "str"
type Demo3 = Trim<' str'> // type Demo3 = "str"
type Demo4 = Trim<'str '> // type Demo4 = "str"
type Demo5 = Trim<' str '> // type Demo5 = "str"
type Demo6 = Trim<' \n\t foo bar \t'> // type Demo6 = "foo bar"
type Demo7 = Trim<''> // type Demo7 = ""
type Demo8 = Trim<' \n\t '> // type Demo8 = ""
- Trim Left:实现 TrimLeft ,它接收确定的字符串类型并返回一个新的字符串,其中新返回的字符串删除了原字符串开头的空白字符串。
type trimed = TrimLeft<' Hello World '> // 应推导出 'Hello World '
思路:
该题目和上题一样:使用${}模板自变量语法配合infer 关键字类型在结合extends判断语句结合递归操作就可以推断最后目标类型
解答:
type TrimLeft<S extends string> = S extends `${' ' | '\n' | '\t'}${infer R}` ? TrimLeft<R> : S
type Demo = TrimLeft<'str'> // type Demo = "str"
type Demo2 = TrimLeft<' str'> // type Demo2 = "str"
type Demo3 = TrimLeft<' str'> // type Demo3 = "str"
type Demo5 = TrimLeft<' str '> // type Demo5 = "str "
type Demo6 = TrimLeft<' \n\t foo bar '> // type Demo6 = "foo bar "
type Demo7 = TrimLeft<''> // type Demo7 = ""
type Demo8 = TrimLeft<' \n\t'> // type Demo8 = ""