前端修补匠

V1

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 UT联合类型时,实际上发生的是 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

分类:

前端

标签:

前端

作者介绍

前端修补匠
V1