开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
大家好,我是初心,本篇是我坚持原创文章的第02期文章,如有错误,欢迎指正👏🏻
TS现状
介绍类型体操之前,容我讲个笑话,其实我一直在内卷TypeScript
,却未尝试过项目实战,学了忘,忘了又学,一直循环;
后面无意发现了TS
有类型体操,预期是想通过类型体操深入学习TS
,打破目前困局。
什么是类型体操
那么什么是类型体操呢,类型体操来源 type-challenges 项目,其意在于更好的了解 TS 的类型系统,编写自己的类型工具,也有种只是单纯的享受挑战的乐趣!
type-challenges 的高质量类型可以提高项目的可维护性并避免一些潜在的漏洞。
知道了什么是类型体操,让我们正式开始吧。
题目介绍
实现 TS 内置的 Pick<T, K>,但不可以使用它。
从类型 T 中选择出属性 K ,构造成一个新的类型。
例如:
// 通过interface 定义了 Todo
interface Todo {
title: string
description: string
completed: boolean
}
// 挑选出 title 和 completed
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
const todo: TodoPreview = {
title: '云层上的光',
completed: false,
}
例子中interface
定义了三个属性并定义了类型,MyPick
从中挑选出 title
和 completed
,这样 todo 声明的变量就必须是title
和 completed
且类型分别是 字符串和布尔类型。
解题思路
熟悉Pick
的童鞋对于这道题简直就是so一贼
,不熟悉的童鞋也不要紧,Pick
其实是 TS 内置方法,Pick
的作用就是从一个对象中挑选需要的字段出来,比如从Todo里面只取出title
和completed
在没有实现 Pick
我们可以这样处理,重新声明一个新的类型
interface TodoPreviewType{
title: string
completed: boolean
}
这样做的好处确实可以解决这个问题,但是类型体操是让我们实现MyPick
MyPick实现
讲实话,初次接触类型体操,即使我有学习过TS
可是还是做不出来,所以我们看看Issues
的实现
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
短短的3行代码就实现了TS
内置的Pick
,简直是不可思议。
TS中keyof、extends、in原理
首先我们看看上文中keyof
、extends
、in
在TS中分别代表着什么含义?
keyof原理
TS 中的keyof
的作用等价于 JS 中的Object.keys
// keyof
interface Person {
name: string;
age: number;
gender: string;
}
// 此时的 P 就是一个联合类型
type P = keyof Person; // "name" | "age" | "gender"
extends原理
TS 中的extends
有2个作用,第1个是继承 第2个是判断
// 第一种 继承
interface Person{
name: string;
age: number;
}
// A 继承了 Person 所有的类型
interface A extends Person{
gender: string;
}
// 第二种 判断
interface B{
name: string;
}
// 判断 B 是否 >= Person 也就是说 B的类型必须要多余或者等于 Person 才会是 true
type b = B extends Person ? true: false;// b === false
// 判断 1 是否是 number 类型
type isNnumber = 1 extends number ? true : false;
in原理
TS 中 in 其实和 JS 中的 in 用法一致,作用类似JS中的for...in或者for...of
MyPick实现原理
// MyPick实现原理
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
- 目光聚集在泛型中
<T, K extends keyof T>
此时的T代表的是谁呢?K 又代表的谁呢 - 在使用中我们可以看到
type TodoPreview = MyPick<Todo, 'title' | 'completed'>
- 显而易见 T 其实就是 Todo。 K的话其实就是联合类型 'title' | 'completed'
- 那么
k extends keyof T
检测 K是否符合 Todo 的类型 [P in K]: T[P]
左边为循环,其中P就是循环的key,K则是联合类型(title | completed) 解析起来就是 [key in ('title' | 'completed')] : Todo[key]- 至此MyPick就算结束了。
总结
Pick 从一个对象中挑选需要的字段出来,挑选出来的字段取决于第二个参数。