TypeScript 作为 JavaScript 的超集,其强大的类型系统为开发者提供了更安全、更可维护的代码编写体验。而工具类型(Utility Types)则是 TypeScript 类型系统中的一把利器,它允许我们通过操作和转换现有类型来创建新的类型,从而极大地提升了代码的灵活性和可复用性。
本文将深入探讨 TypeScript 工具类型,带你领略其强大之处,并掌握如何利用它们提升代码质量。
工具类型本质上是一些预定义的类型别名,它们接收一个或多个类型参数,并返回一个新的类型。TypeScript 内置了许多实用的工具类型,以下是常见的工具类型及其用法示例。
将类型 T
的所有属性设置为可选。
使用场景:
当你需要创建一个对象,但不确定是否包含所有属性时,可以使用 Partial
。
示例:
interface User {
name: string;
age: number;
email: string;
}
// 使用 Partial 将所有属性变为可选
type PartialUser = Partial<User>;
const user1: PartialUser = { name: "Alice" }; // 合法
const user2: PartialUser = { age: 25 }; // 合法
const user3: PartialUser = {}; // 合法
将类型 T
的所有属性设置为必选。
使用场景:
当你需要确保一个对象包含所有属性时,可以使用 Required
。
示例:
interface User {
name?: string;
age?: number;
email?: string;
}
// 使用 Required 将所有属性变为必选
type RequiredUser = Required<User>;
const user1: RequiredUser = { name: "Alice", age: 25, email: "[email protected]" }; // 合法
const user2: RequiredUser = { name: "Bob" }; // 错误:缺少 age 和 email
将类型 T
的所有属性设置为只读。
使用场景:
当你需要创建一个不可变的对象时,可以使用 Readonly
。
示例:
interface User {
name: string;
age: number;
}
// 使用 Readonly 将所有属性变为只读
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = { name: "Alice", age: 25 };
user.name = "Bob"; // 错误:无法分配到 "name",因为它是只读属性
创建一个对象类型,其属性键为 K
类型,属性值为 T
类型。
使用场景:
当你需要定义一个键值对对象时,可以使用 Record
。
示例:
type UserRole = "admin" | "user" | "guest";
// 使用 Record 定义角色对应的权限
type RolePermissions = Record<UserRole, string[]>;
const permissions: RolePermissions = {
admin: ["create", "read", "update", "delete"],
user: ["read", "update"],
guest: ["read"],
};
从类型 T
中选择指定属性 K
来构造新类型。
使用场景:
当你只需要一个类型的部分属性时,可以使用 Pick
。
示例:
interface User {
name: string;
age: number;
email: string;
}
// 使用 Pick 选择 name 和 email 属性
type UserContactInfo = Pick<User, "name" | "email">;
const contactInfo: UserContactInfo = {
name: "Alice",
email: "[email protected]",
};
从类型 T
中排除指定属性 K
来构造新类型。
使用场景:
当你需要排除一个类型的某些属性时,可以使用 Omit
。
示例:
interface User {
name: string;
age: number;
email: string;
}
// 使用 Omit 排除 age 属性
type UserWithoutAge = Omit<User, "age">;
const user: UserWithoutAge = {
name: "Alice",
email: "[email protected]",
};
从类型 T
中排除可以赋值给 U
的类型。
使用场景:
当你需要从联合类型中排除某些类型时,可以使用 Exclude
。
示例:
type Animal = "dog" | "cat" | "bird" | "fish";
// 使用 Exclude 排除 "bird" 和 "fish"
type LandAnimal = Exclude<Animal, "bird" | "fish">;
const animal: LandAnimal = "dog"; // 合法
const animal2: LandAnimal = "bird"; // 错误:类型“"bird"”不可分配给类型“"dog" | "cat"”
从类型 T
中提取可以赋值给 U
的类型。
使用场景:
当你需要从联合类型中提取某些类型时,可以使用 Extract
。
示例:
type Animal = "dog" | "cat" | "bird" | "fish";
// 使用 Extract 提取 "cat" 和 "dog"
type Pet = Extract<Animal, "cat" | "dog">;
const pet: Pet = "cat"; // 合法
const pet2: Pet = "fish"; // 错误:类型“"fish"”不可分配给类型“"cat" | "dog"”
从类型 T
中排除 null
和 undefined
。
使用场景:
当你需要确保一个类型不为 null
或 undefined
时,可以使用 NonNullable
。
示例:
type MaybeString = string | null | undefined;
// 使用 NonNullable 排除 null 和 undefined
type DefinitelyString = NonNullable<MaybeString>;
const str1: DefinitelyString = "Hello"; // 合法
const str2: DefinitelyString = null; // 错误:不能将类型“null”分配给类型“string”
获取函数类型 T
的返回值类型。
使用场景:
当你需要提取函数的返回值类型时,可以使用 ReturnType
。
示例:
function getUserInfo() {
return { name: "Alice", age: 25 };
}
// 使用 ReturnType 获取 getUserInfo 的返回值类型
type UserInfo = ReturnType<typeof getUserInfo>;
const user: UserInfo = { name: "Bob", age: 30 }; // 合法
除了内置的工具类型,我们还可以根据需求自定义工具类型。例如,我们可以定义一个 Nullable
类型,将类型 T
转换为可空类型:
type Nullable<T> = T | null;
示例:
type MaybeString = Nullable<string>;
const str1: MaybeString = "Hello"; // 合法
const str2: MaybeString = null; // 合法
TypeScript 工具类型是提升代码质量和开发效率的利器。通过熟练掌握工具类型的使用,我们可以编写出更加简洁、可读、可维护的类型安全代码。希望本文的示例和解释能帮助你更好地理解和使用这些工具类型!
附录:
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏和分享!