原创: 前端修补匠(微信公众号ID:codeTK),欢迎分享,非公众号转载保留此声明。
✨『前言』
哈喽~这里是前端修补匠!和我一起进行「4月更文挑战」,一起养成写作习惯!
按着官方文档学了一遍TypeScript,但是平时对TypeScript的使用还停留在很浅的水平。
古话说的好,『纸上得来终觉浅,绝知此事要躬行』。所以我们根据 GitHub 上的『TypeChallenge』进行实现,修补一下TypeScript的知识吧~
🔨『Pick<Type, Keys>』
TypeScript内置类型,用于从一个类型中选取指定Key的属性,组成一个新的类型。
✋『用法』
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
};
//{ title: string; completed: boolean; }
🚀『实现』
type MyPick<T, P extends keyof T> = {
[K in P]: T[K]
}
📖『详解』
我们需要从联合类型 P 中取得所有内容,并且进行遍历,然后返回一个仅仅包含这些键的新类型。这里使用到了映射和查找类型的知识点:
- 类型约束:
P extends keyof T是一种约束,表明P必须是T的键集合的子集。 - 查找类型:允许我们通过名称从另一个类型中提取一个类型。类似于使用键值从一个对象中获取值。
- 映射类型:允许我们将一个类型中的每个属性转换为一个新类型。
🔨『Exclude<UnionType, ExcludedMembers>』
从联合类型 T 中剔除属于 U 类型的子集,生成一个新的类型。简单来说就是: T 取和 U 的差集。
✋『用法』
type T0 = Exclude<"a" | "b" | "c", "a">;//type T0 = "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">;//type T1 = "c"
type T2 = Exclude<string | number | (() => void), Function>;//type T2 = string | number
🚀『实现』
type MyExclude<T,U>=T extends U ? never : T;
📖『详解』
TypeScript 中的条件类型 是『可分配的』。
所以 T extends U 且 T 是联合类型时,实际上发生的是 TypeScript 遍历联合类型 T 并将条件应用到每个元素上。
也就是说:
=> 'a'|'b'|'c' extends 'a'|'d'|'f'
=> (
'a' extends 'a'|'d'|'f' ? never : 'a' |
'b' extends 'a'|'d'|'f' ? never : 'b' |
'c' extends 'a'|'d'|'f' ? never : 'c'
)
=> 'b'|'c'
🔨『Omit<Type, Keys>』
从类型 T 中 排除 K 键的属性, 生成一个新的类型。简单点说:T 的键和 K 取差集为新类型的键,键的类型即为 在 T 中的类型。
✋『用法』
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
type TodoPreview = Omit<Todo, "description">;
const todo: TodoPreview = {
title: "Clean room",
completed: false,
createdAt: 1615544252770,
};
🚀『实现』
type MyOmit<T,K> = MyPick<T,MyExclude<keyof T,K>>
📖『详解』
我们这里需要返回一个新的对象类型,但不指定键。显然,这提示我们需要在这里使用映射类型(mapped types)。
我们需要映射对象的每个属性并构造一个新类型。让我们从基础开始,构建相同的对象:
type MyOmit<T, K> = { [P in keyof T]: T[P] };
在这里,我们遍历了 T 中的所有键,将其映射到类型 P,并使其成为新对象的键,同时值为 T[P] 类型。
这样,我们就可以遍历所有的键,但是我们需要过滤掉那些我们不感兴趣的键。
为了实现这一点,我们可以使用 “as” 语法重新映射键类型:
type MyOmit<T, K> = { [P in keyof T as P extends K ? never : P]: T[P] };
我们映射 T 的所有属性,如果属性在 K 联合中,我们返回 “never” 类型作为它的键 ,否则返回键本身。这样,我们就可以过滤掉属性并获得所需的对象类型。
最后使用之前实现的『Pick<Type, Keys>』和『Exclude<UnionType, ExcludedMembers>』进行简化,得到最简单的形式。