使用实用类型转换 TypeScript 中的类型
有时,你会遇到需要某种类型变体的情况。例如,你可能需要省略某些键,只保留某些键,甚至将某个类型的所有键标记为未定义或必需,等等。
TypeScript 提供了实用类型(Utility Types),旨在解决这个问题。本文将介绍这些内置的实用类型,以及一个提供更多实用功能的第三方库(附带示例),这些功能或许能帮助您实现上述目标。
内置实用程序类型
本节重点介绍 TypeScript 内置的实用类型,它们数量众多,我无法一一介绍,我只会根据自己的理解,举例说明几个关键类型。
部分的
此实用程序类型从现有类型构造一个新类型,顶层键被标记为可选(?)。
interface Type {
field: string;
}
type Type2 = Partial<Type>;
注意:此设置仅作用于一层,这意味着低于一层的键不会受到影响。如果您想将所有键标记为可选,无论它们位于哪一层,请查看下方的 PartialDeep 选项。
必需的
这种实用类型的作用与上述相反,它会创建一个新类型,并将旧类型中所有可选的键标记为必需。
interface Type {
field?: string;
optional?: string;
}
type Type2 = Required<Type>;
忽略
此实用工具类型从现有类型构造一个新类型,同时从新类型中省略指定的键。
interface Type {
field1?: string;
field2: string;
field3: string;
}
type Type2 = Omit<Type, "field3" | "field1">;
挑选
这种实用工具类型通过从旧类型中选择指定的键来构造一个新类型。它的功能与上述的“省略”操作相反。
interface Type {
field1?: string;
field2: string;
field3?: string;
field4: string;
field5?: string;
}
type Type2 = Pick<Type, "field2" | "field3">;
只读
此实用程序类型从现有类型构造一个新类型,并将所有键标记为只读,即它们不能被重新赋值。这对于冻结对象的类型非常有用,例如Object.freeze():
interface Type {
field1?: string;
field2: string;
field3: string;
}
type Type2 = Readonly<Type>;
记录
该实用类型构造一个新类型,其中联合成员作为键,类型作为键的类型。
interface Name {
firstName: string;
lastName: string;
}
type Names = "user1" | "user2";
type Type2 = Record<Names, Name>;
以上是一些我觉得非常有用的内置实用程序类型,您可以在此处的官方文档中找到更多关于内置实用程序类型的信息。
扩展内置实用程序类型
虽然上述内置实用类型非常强大,但它们并不能涵盖所有使用场景,而这正是提供更多实用功能的库发挥作用的地方。type -fest就是一个很好的例子,它提供了更多实用功能。
虽然我不会深入研究 type-fest 提供的所有实用程序,但我会重点介绍一些非常有用的、基于内置类型实用程序的实用程序。
除了
这是上述 Omit 工具类型的一个变体,但更为严格。它通过从现有类型中省略指定的键来构造一个新类型,但与 Omit 不同的是,被省略的键必须严格存在于现有类型中。
// import { Except } from "type-fest"
interface X {
a: string;
b: string;
c: string;
}
// Omit Example
type Y = Omit<X, "d">
// Except Example
type Z = Except<X, "d" >
如下面的图片所示,如果您提供的键不存在,Except 会抛出错误。
合并
通过合并两种类型来构造一种新类型,其中第二种类型的键会覆盖第一种类型的键。
// import { Merge } from "type-fest"
interface X {
a: string;
b: string;
c: string;
}
interface Y {
c: number;
d: number;
e: number;
}
type Z = Merge<X, Y>
const x : Z = {
a: "is string",
b: "is string",
c: 1,
d: 2,
e: 3,
}
部分深度
这种实用工具类型会创建一个新类型,其中所有层级的所有键都是可选的。它与Partial内置的实用工具类型非常相似,但有一个显著区别:它会遍历所有层级,而前者只在第一层级生效。
// import { PartialDeep } from "type-fest";
interface X {
a: string;
b: string;
c: string;
}
interface Y {
c: number;
d: number;
e: number;
f: X;
}
type Z = PartialDeep<Y>;
const x: Z = {};
ReadonlyDeep
这种实用工具类型会创建一个新类型,并将所有层级的所有键都标记为必需。它与内置Readonly实用工具类型类似,但与内置实用工具类型不同的是,这种类型会遍历所有层级的所有键,从而使它们成为不可变的。
可变
这种实用类型构造一个类型,该类型从类型中的键中剥离readonly,本质上与内置实用类型的作用相反Readonly。
// import { Mutable } from "type-fest";
interface X {
readonly a: string;
readonly d: string;
}
type Y = Mutable<X>;
结论
在本文中,我研究了 TypeScript 实用类型,以及它们如何帮助您从现有类型自动创建类型,而不会导致重复,从而无需保持相关类型同步。
我重点介绍了一些我在日常开发工作中特别常用的内置实用类型。此外,我们还研究了 type-fest,这是一个包含大量实用类型的库,它扩展了内置类型,我们也重点介绍了其中的一些类型。










