题目描述

实现 TS 内置的 Pick<T, K>,但不可以使用它。

从类型 T 中选择出属性 **K**,构造成一个新的类型

例如:

  1. interface Todo {
  2. title: string
  3. description: string
  4. completed: boolean
  5. }
  6. type TodoPreview = MyPick<Todo, 'title' | 'completed'>
  7. const todo: TodoPreview = {
  8. title: 'Clean room',
  9. completed: false,
  10. }

题目解答

Pick<T, K> 类型用于从T类型中选择部分属性K来构造新的类型。

首先,我们需要遍历对象 T。那就要使用映射类型来遍历:

  1. type MappedType<T> = {
  2. [Key in keyof T]: T[Key];
  3. };
  • keyof T用于从对象类型T中获取键值 key
  • in用于对对象键值key进行迭代;
  • Key 就是对象键值 key 本身;
  • T[Key]是指定 Key 的值;

然后,要想迭代获取对象的某个部分,就需要指定要迭代的key

  1. type MappedType<T, Keys> = {
  2. [Key in Keys]: T[Key];
  3. };

但是,这样写就会有两个错误:

  • 不能将类型“Keys”分配给类型“string | number | symbol”。
  • 类型“Key”无法用于索引类型“T”。

这两个错误都与迭代规则有关:

  1. key 可以是stringnumbersymbol
  2. 如果T中不存在Key,就不能调用T[Key]

如果规则 2 成立,那么规则 1 一定是成立的,因为现有的 keys 是指定类型之一。为了迭代现有的 key,我们需要使用extends关键字进行约束。这样,如果指定不存在的 key,TypeScript 将抛出一个错误,如果T中不存在这个 key,就不能调用T[key]

Pick的实现如下:

  1. type MyPick<T, Keys extends keyof T> = {
  2. [Key in Keys]: T[Key];
  3. };

image.png