Skip to Content

面试导航 - 程序员面试题库大全 | 前端后端面试真题 | 面试

Typescript高级类型:Omit

Omit 是 TypeScript 提供的一个高级类型工具,用于从一个类型中排除指定的键,从而构造一个新的类型。它在处理对象类型时非常有用,可以帮助你轻松创建不包含某些特定属性的类型。

它的主要使用场景有以下几个方面:

  1. 去除不需要的属性:当你有一个类型,但不需要其中的一些属性时,可以使用 Omit 去除这些属性。

  2. 创建子类型:从一个大型类型中派生出较小的子类型,只包含某些特定的属性。

Omit 的基本使用

假设我们有一个用户类型 User:

interface User { id: number; name: string; email: string; password: string; }

我们可以使用 Omit 创建一个新的类型,该类型不包含 password 属性:

type UserWithoutPassword = Omit<User, 'password'>; const user: UserWithoutPassword = { id: 1, name: 'Moment', email: 'moment@qq.com', };

我们还可以排除多个属性,只需将属性名用联合类型 | 连接起来:

type BasicUserInfo = Omit<User, 'email' | 'password'>; const basicUser: BasicUserInfo = { id: 1, name: 'moment', };

Omit 的基本实现

Omit 的定义如下:

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

在上面的代码中 T 是一个泛型,代表一个对象类型。K 是一个泛型,代表要从 T 中剔除的键。K 必须是 keyof any 的子集,也就是说,K 可以是任何类型的键。

Pick<T, Exclude<keyof T, K>> 从类型 T 中挑选出 Exclude<keyof T, K> 中的键。

进阶使用

动态类型与 Omit 结合使用

结合条件类型和 Omit 可以实现更加动态的类型操作。

interface User { id: number; name: string; email: string; password: string; } type ConditionalOmit<T, K extends keyof any, U> = T extends U ? Omit<T, K> : T; type AdminUser = User & { admin: true }; type RegularUser = User & { admin?: false }; type UserWithoutPassword<T> = ConditionalOmit<T, 'password', { admin?: false }>; const adminUser: UserWithoutPassword<AdminUser> = { id: 1, name: 'moment', email: 'moment@qq.com', password: 'moment', admin: true, }; const regularUser: UserWithoutPassword<RegularUser> = { id: 2, name: 'm', email: 'm@qq.com', // password 被省略 };

在上面的这些代码中包含了一个条件类型 ConditionalOmit:

type ConditionalOmit<T, K extends keyof any, U> = T extends U ? Omit<T, K> : T;

它的主要作用是用于根据某些条件有选择性地移除类型中的属性:

  1. T 是输入类型。

  2. K 是要移除的属性。

  3. U 是条件类型。

条件类型 T extends U ? Omit<T, K> : T 的含义是:

  1. 如果 T 可以赋值给类型 U,则从 T 中移除属性 K(通过 Omit<T, K> 实现)。

  2. 否则,保留类型 T 不变。

最终实现有条件移除 Password 属性的类型 UserWithoutPassword:

  1. 如果 T 满足 { admin?: false } 条件(即普通用户),则移除 T 中的 password 属性。

  2. 否则(即管理员用户),保留 T 不变。

递归 Omit

通过递归类型实现嵌套类型的 Omit 操作。

interface NestedObject { id: number; details: { name: string; email: string; address: { street: string; city: string; }; }; } type DeepOmitHelper<T, K extends keyof any> = { [P in keyof T]: P extends K ? never : T[P] extends infer TP ? TP extends object ? DeepOmit<TP, K> : TP : never; }; type DeepOmit<T, K extends keyof any> = Pick< DeepOmitHelper<T, K>, { [P in keyof DeepOmitHelper<T, K>]: DeepOmitHelper<T, K>[P] extends never ? never : P; }[keyof DeepOmitHelper<T, K>] >; type NestedWithoutEmail = DeepOmit<NestedObject, 'email'>; const nestedObject: NestedWithoutEmail = { id: 1, details: { name: 'moment', address: { street: '中山大道', city: '珠海', }, }, // email 被省略 };

对于上面的代码主要有以下几个方面的解释:

  1. DeepOmitHelper 类型:

    • DeepOmitHelper 是一个辅助类型,用于处理嵌套对象。

    • 对于每个属性 P,如果 P 是要删除的属性 K,则将其类型设置为 never。

    • 如果属性 P 是一个对象,则递归应用 DeepOmit。

    • 否则,保持属性类型不变。

  2. DeepOmit 类型:

    • 使用 Pick 和映射类型来删除被设置为 never 的属性。

    • Pick<DeepOmitHelper<T, K>, {...}> 从 DeepOmitHelper 中挑选出所有非 never 的属性键,创建一个新的类型。

最终实现 NestedWithoutEmail 类型是从 NestedObject 中递归删除 email 属性后的结果。

使用 Omit 构建 REST API 响应类型

在构建 REST API 时,常常需要对请求和响应的类型进行严格的控制。

interface User { id: number; name: string; email: string; password: string; createdAt: Date; updatedAt: Date; } // 创建一个请求体类型,省略 id 和时间戳 type CreateUserRequest = Omit<User, 'id' | 'createdAt' | 'updatedAt'>; const newUser: CreateUserRequest = { name: 'moment', email: 'moment@qq.com', password: 'moment', }; // 创建一个响应体类型,省略 password type UserResponse = Omit<User, 'password'>; const userResponse: UserResponse = { id: 1, name: 'moment', email: 'moment@qq.com', createdAt: new Date(), updatedAt: new Date(), // password 被省略 };

总结

Omit 是一个非常强大的工具类型,通过结合条件类型、联合类型、递归类型和映射类型等高级类型特性,可以实现复杂的类型操作。它在很多场景下都非常有用,例如创建请求和响应类型、动态属性过滤、构建嵌套对象类型等。通过灵活运用 Omit,可以使 TypeScript 代码更加灵活和类型安全,提高代码的可维护性和可读性。

最后更新于:
Copyright © 2025Moment版权所有粤ICP备2025376666