Skip to Content

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

Typescript高级类型:Pick

Pick 是 TypeScript 中的一个实用类型,用于从已有的类型中选择一组属性,生成一个新的类型。它可以帮助我们在代码中更精细地控制类型,从而提高代码的类型安全性和可维护性。

基本使用

假设我们有一个 User 类型:

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

我们想创建一个新的类型,只包含 name 和 email 属性。我们可以使用 Pick 来实现:

type UserContactInfo = Pick<User, 'name' | 'email'>; const contactInfo: UserContactInfo = { name: 'Moment', email: 'moment@qq.com', };

实际的应用

Pick 在实际开发中非常有用,尤其是在处理大型接口或模型时。常见的应用场景包括:

  1. 选择性暴露接口,在 API 返回值或前端组件中,只暴露必要的属性:
type PublicUserInfo = Pick<User, 'name' | 'email'>;
  1. 简化类型定义,在处理复杂的类型或接口时,可以简化类型定义,避免重复代码:
interface CreateUserRequest extends Pick<User, 'name' | 'email' | 'age'> {}
  1. 类型约束,在函数参数中,只允许特定的属性:
function sendEmail(user: Pick<User, 'email'>) {}

实现原理

Pick 类型的实现原理如下所示:

type Pick<T, K extends keyof T> = { [P in K]: T[P]; };

在上面的代码中:

  1. T 是源类型。

  2. K 是一个属性名的联合类型,表示要从 T 中选取的属性。

  3. P in K 表示循环 K 中的每个属性 P,并将其添加到新的类型中。

  4. T[P] 表示 T 类型中属性 P 的类型。

进阶使用

结合泛型函数使用

我们可以定义一个泛型函数,使用 Pick 来选择参数类型的部分属性:

interface User { id: number; name: string; email: string; age: number; address: string; } function getUserInfo<T extends keyof User>(user: User, keys: T[]): Pick<User, T> { const result = {} as Pick<User, T>; keys.forEach((key) => { result[key] = user[key]; }); return result; } const user: User = { id: 1, name: 'Moment', email: 'moment@qq.com', age: 18, address: '西安', }; const userInfo = getUserInfo(user, ['name', 'email']); console.log(userInfo);

最终输出结果如下所示:

动态选择属性

通过结合条件类型、映射类型、索引类型查询、索引访问类型和工具类型,实现查找出接口中的可选类型:

interface User { id: number; name: string; email: string; age: number; address?: string; } // 判断属性是否为可选 type IsOptional<T, K extends keyof T> = {} extends Pick<T, K> ? K : never; // 提取可选属性的键,并排除掉 undefined 类型 type OptionalKeys<T> = Exclude< { [K in keyof T]: IsOptional<T, K>; }[keyof T], undefined >; // 使用 Pick 提取可选属性的类型 type UserOptionalProperties = Pick<User, OptionalKeys<User>>; const userOptionalProps: UserOptionalProperties = { address: '广州', }; console.log(userOptionalProps);

在上面的代码中,条件类型允许我们根据类型的特性来选择不同的类型。条件类型的基本形式是 T extends U ? X : Y,意思是如果类型 T 能够赋值给类型 U,则结果是类型 X,否则是类型 Y。

type IsOptional<T, K extends keyof T> = {} extends Pick<T, K> ? K : never;

这里 {} extends Pick<T, K> 检查 {} 是否能赋值给 Pick<T, K>,即属性 K 是否可选。如果可选,结果为 K,否则为 never。

深层属性选择

使用递归类型,可以实现从嵌套对象中选择属性。

interface Address { street: string; city: string; } interface User { id: number; name: string; email: string; age: number; address: Address; } // 递归地选择深层属性 type DeepPick<T, K extends keyof T> = { [P in K]: T[P] extends object ? DeepPick<T[P], keyof T[P]> : T[P]; }; type UserAddressOnly = DeepPick<User, 'address'>; const example: UserAddressOnly = { address: { street: '中山大道', city: '广州', }, };

条件类型与 Pick 结合使用

我们可以使用条件类型来选择符合特定条件的属性:

interface User { id: number; name: string; email: string; age: number; isActive: boolean; } // 选择布尔类型的属性 type BooleanProperties<T> = { [K in keyof T]: T[K] extends boolean ? K : never; }[keyof T]; type UserBooleanProperties = Pick<User, BooleanProperties<User>>; const boo: UserBooleanProperties = { isActive: false, };

最终类型如下图所示:

结合 Exclude 使用

我们可以结合 Pick 和 Exclude 来实现复杂的类型选择:

interface User { id: number; name: string; email: string; age: number; address: string; isActive: boolean; } // 排除特定类型的属性 type ExcludeProperties<T, U> = { [K in keyof T]: T[K] extends U ? never : K; }[keyof T]; type NonStringProperties<T> = Pick<T, ExcludeProperties<T, string>>; type UserNonStringProperties = NonStringProperties<User>; const user: UserNonStringProperties = { age: 18, id: 7, isActive: true, };

最终类型如下图所示:

总结

Pick 是 TypeScript 中一个强大的实用类型,允许你从现有类型中选择特定的属性,创建新的类型。

通过这些高级用法示例,我们可以看到 Pick 类型在 TypeScript 中的强大和灵活性。合理使用这些技术可以帮助你编写更健壮和可维护的类型安全代码。

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