
前端修补匠
2023/04/02阅读:26主题:红绯
『Type Challenge』Pick | Exclude | Omit
“原创: 前端修补匠(微信公众号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>』
进行简化,得到最简单的形式。
“ ”
『参考』
Type Challenges Solutions TypeScript: Documentation - Utility Types
作者介绍
