TypeScript 类型体操:提取对象指定 key 并设置为必填

2022-12-21 19:55:30 浏览数 (1)

大家好,我是前端西瓜哥。今天我们来做一道 TypeScript 类型编程题。

我们需要实现一个 RequiredPick 类,从一个对象类型中提取指定的 key 生成新的对象类型,并将它的所有 key 设置为必填。

代码语言:javascript复制
type RequiredPick<T, K> = any // 完成这个类型

type Obj = {
  a: number;
  b?: string;
  c: boolean;
}

type ResType = RequiredPick<Obj, 'a' | 'b'>;
// 上面的类型要和下面的类型相等
type ExpectedType = {
  a: number;
  b: string; // 注意这里没有可选标识 ?
}

如果你想要真正判断两个类型是否相等,而且是靠肉眼确认,这里有一个用于比较的高级类型:

代码语言:javascript复制
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false

Equal 接受两个类型,如果相等返回 true,不相等返回 false。

Pick

我们容易想到 Pick 的实现,Pick 是 TypeScript 内置的一个高级类型。这个类型的实现在我以前的文章《类型体操:探究 TypeScript 内置高级类型》有讲解过。

它的实现如下:

代码语言:javascript复制
/**
 * From T, pick a set of properties whose keys are in the union K
 */
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Pick 接受两个类型 T 和 K,K 必须为 T 对象的 key 组成的联合类型的子类型。

{ [P in K]: T[P]; } 是对类型进行 重映射,这里的 P in K 表示遍历 K(K 是遍历类型),然后作为重映射类型的新 key,并且将 T[P] 作为值。

关于 Mapped Types(重映射),更多说明可以看这篇官方文档:

https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

可选 -> 必填

Pick 不能将可选的 key 变成必选的,我们需要在这上面做一些调整。

没错,很简单。。。只需要 : 前边加上 -?

实现为:

代码语言:javascript复制
type RequiredPick<T, K extends keyof T> = {
    [P in K]-?: T[P];
};

除了有 -? 将key 替换为必选,我们还有 -readonly 的写法,将只读 key 转换为普通 key。

然后打个广告,前端大佬神光的 TypeScript 体操教材,如果你想入门的话,这个挺适合,也不贵。

结尾

如果你想练习类型编程,可以尝试做 github 上一个名为 type-challenges 的项目的题目。

我是前端西瓜哥,欢迎关注我,学习更多知识。


0 人点赞