【Typescript 系列】类型体操之中等篇题型(第四节)解读

91 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情

1. 引言

接着上一节中,接下来我们继续Ts中等篇的题型练习 https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md 提供的TypeScript 类型体操姿势合集题型,目的是为了让大家更好的了解TS的类型系统,编写自己的类型工具,或者单纯的享受挑战的乐趣!

2. 题型

  1. 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
  1. 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 = ""
  1. 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 = ""