题目描述
实现 TS 内置的 Pick<T, K>
,但不可以使用它。
从类型 T 中选择出属性 **K**
,构造成一个新的类型。
例如:
interface Todo {
title: string
description: string
completed: boolean
}
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
}
题目解答
Pick<T, K>
类型用于从T
类型中选择部分属性K
来构造新的类型。
首先,我们需要遍历对象 T
。那就要使用映射类型来遍历:
type MappedType<T> = {
[Key in keyof T]: T[Key];
};
keyof T
用于从对象类型T中获取键值key
;in
用于对对象键值key
进行迭代;Key
就是对象键值key
本身;T[Key]
是指定Key
的值;
然后,要想迭代获取对象的某个部分,就需要指定要迭代的key
:
type MappedType<T, Keys> = {
[Key in Keys]: T[Key];
};
但是,这样写就会有两个错误:
- 不能将类型“Keys”分配给类型“string | number | symbol”。
- 类型“Key”无法用于索引类型“T”。
这两个错误都与迭代规则有关:
key
可以是string
、number
、symbol
;- 如果
T
中不存在Key
,就不能调用T[Key]
。
如果规则 2 成立,那么规则 1 一定是成立的,因为现有的 keys
是指定类型之一。为了迭代现有的 key
,我们需要使用extends
关键字进行约束。这样,如果指定不存在的 key
,TypeScript 将抛出一个错误,如果T
中不存在这个 key
,就不能调用T[key]
。
Pick
的实现如下:
type MyPick<T, Keys extends keyof T> = {
[Key in Keys]: T[Key];
};