TypeScript
TS-Chalenge
TS 类型体操刷题记录 - Easy 篇 (1)
5/21/2022
·
271
·
profile photo

实现 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
 * }
 */
也是符合要求的🥳。