TS 类型体操刷题记录 - Easy 篇 (1)

352 阅读1分钟

实现 Pick

题目: 传送门

从类型 T 中选择出包含在集合 K 中的属性,构造成一个新的类型。(即实现 TS 内置的 Pick<T, K>

例如:

interface Todo {
  title: string
  description: string
  completed: boolean
}

type TodoPreview = MyPick<Todo, 'title' | 'completed'>

思路与要点:

TS 中,可以使用 extends 运算符来判断一个属性是否在集合类型 Union Type 中:

例如:

type r1 = 'title' extends 'title' | 'completed' ? true : false // type r1 = true

利用这个特性,我们可以实现这样一种类型:

type MyPick<T, P> = {
  [K in keyof T]: K extends P ? never : T[K]
}

但这样我们会发现,不属于类型 P 的属性会变成 never

type r2 = MyPick<Todo, 'title' | 'completed'>
/**
 * type r2 = {
 *   title: string
 *   description: never
 *   completed: boolean
 *  }
 */

由此,我们需要排除掉 K 中不属于 P 的类型,可以实现一个工具类型 Exclude

type Exclude<T, U> = T extends U ? never : T

然后改造 MyPick 的实现形式:

type MyPick<T, P extends keyof T /* 约束 P 的类型,只允许从 T 的属性中取值 */> = {
  [K in Exclude<keyof T, P>]: T[K]
}

来看下最后的结果:

type r3 = MyPick<Todo, 'title' | 'completed'>
/**
 * type r3 = {
 *   title: string
 *   completed: boolean
 *  }
 */

符合要求🥳。

实现 Readonly

题目:传送门

类型 T 中所有的属性,标记为 readonly。(即实现 TS 内置的 Readonly<T>

例如:

interface Todo {
  title: string
  description: string
}

type TodoReadonly = MyReadonly<Todo>
/**
 * type TodoReadonly = {
 *   title: readonly string
 *   description: readonly string
 * }
 */

思路与要点:

这道题考察点比较简单,我们只需要遍历类型 T 中的所有属性,然后给它们加上 readonly 修饰就可以了:

type MyReadonly<T> = {
  [K in keyof T]: readonly T[K]
}

来看下结果:

type r4 = MyReadonly<Todo>
/**
 * type r4 = {
 *   title: readonly string
 *   description: readonly string
 * }
 */

也是符合要求的🥳。