TypeScript 常用泛型工具函数 目录什么是泛型工具类型1. 属性修饰符让类型“变个身”Partial —— 变“全员可选”Required —— 变“全员必选”Readonly —— 变“只读”2. 结构过滤像筛子一样筛选类型Pick —— 只取我要的Omit —— 排除我不要的3. 函数类型侦探提取函数的秘密Parameters —— 提取参数类型ReturnType —— 提取返回值类型4. 映射与构造快速创建结构Record —— 键值对工厂5. 进阶实战手写自定义工具实战 1DeepPartial (深度可选)实战 2Get (点符号访问类型)参考官方文档什么是泛型工具类型简单来说泛型工具类型就是用来操作类型的函数。普通函数是Input - Output如map把数组转换成新数组。泛型工具类型是Type - Type如Partial把所有属性变成可选。TypeScript 内置了大量开箱即用的工具类型覆盖了前端开发 90% 的场景。1. 属性修饰符让类型“变个身”这是最基础也是最高频的一类工具主要用于修改对象属性的读写性或必选性。PartialT—— 变“全员可选”场景当你有一个“编辑用户信息”的表单用户可能只想修改昵称不想改头像。你不需要把所有字段都重写一遍。interface User { id: number; name: string; age: number; avatar: string; } // 场景定义更新接口不需要传 id且其他字段都可选 type UserUpdateForm PartialOmitUser, id; // 等价于 // type UserUpdateForm { // name?: string; // age?: number; // avatar?: string; // } function updateUser(id: number, data: UserUpdateForm) { // ... }RequiredT—— 变“全员必选”场景Partial的反操作。比如从后端拿来的配置对象可能有缺省但在运行时你确保它已经补全了可以用它断言类型。ReadonlyT—— 变“只读”场景Redux 的 State 或者 Vue/React 的 Props 定义防止在组件内部意外修改父级传递的数据。type ReadonlyState Readonly{ count: number; }; // state.count 2; // ❌ Error: Cannot assign to count because it is read-only2. 结构过滤像筛子一样筛选类型如果你只想从大接口中拿几个字段或者剔除几个敏感字段这一类工具是你的救星。PickT, K—— 只取我要的场景后端返回了一个包含 20 个字段的“用户详情”但你只需要渲染一个“用户卡片”只需要id,name,avatar。interface UserDetail { id: number; name: string; email: string; phone: string; passwordHash: string; // 敏感信息 lastLoginIp: string; } // 只需要这三个字段做卡片展示 type UserCardProps PickUserDetail, id | name | avatar;OmitT, K—— 排除我不要的场景创建文章列表数据结构和创建文章表单几乎一样但列表不需要content字段太长了且不需要id新建时没有。interface Article { id: number; title: string; content: string; tags: string[]; } // 新建文章表单不需要 id type CreateArticleDto OmitArticle, id;小技巧Omit其实可以用Pick和Exclude组合实现但 TS 内置了它直接用更爽。3. 函数类型侦探提取函数的秘密在编写高阶组件或装饰器时我们经常需要知道一个函数“接收什么参数”以及“返回什么类型”。ParametersT—— 提取参数类型场景你要写一个日志装饰器包裹任意函数打印它的参数名和值。function logT extends (...args: any[]) any(fn: T) { return function(this: any, ...args: ParametersT) { console.log(Function called with:, args); return fn.apply(this, args); }; } function add(a: number, b: number) { return a b; } const wrappedAdd log(add); // wrappedAdd 的参数类型自动推断为ReturnTypeT—— 提取返回值类型场景异步请求封装时你想基于 API 函数的返回值定义 Redux 的 Action 类型。async function fetchUser(id: number): Promise{ name: string; age: number } { return { name: Jack, age: 18 }; } // 自动推导 fetchUser 返回的 Promise 内部结构 type UserType AwaitedReturnTypetypeof fetchUser; // UserType { name: string; age: number }4. 映射与构造快速创建结构RecordKeys, Type—— 键值对工厂场景定义一个枚举对象或者一个以 ID 为 Key 的字典。// 定义一个角色权限映射 type Role admin | user | guest; type Permission { read: boolean; write: boolean; }; // 快速生成对象结构所有角色的权限列表 type RolePermissions RecordRole, Permission; const permissions: RolePermissions { admin: { read: true, write: true }, user: { read: true, write: false }, guest: { read: false, write: false }, };5. 进阶实战手写自定义工具内置的很好用但有时候我们需要更强大的功能。通过泛型递归和条件类型我们可以自己造“轮子”。实战 1DeepPartial(深度可选)内置的Partial只能处理一层。如果对象是嵌套的我们需要递归地把所有层级的属性都变为可选。type DeepPartialT { [P in keyof T]?: T[P] extends object ? DeepPartialT[P] : T[P]; }; interface Config { server: { host: string; port: number; }; db: { name: string; }; } // 现在嵌套属性也是可选的了 type PartialConfig DeepPartialConfig; // partialConfig.server?.host // 合法实战 2Get(点符号访问类型)类似 Lodash 的_.get但是是在类型层面操作。根据字符串路径获取深层属性的类型。type GetT, P P extends ${infer K}.${infer Rest} ? K extends keyof T ? GetT[K], Rest : never : P extends keyof T ? T[P] : never; interface ApiData { user: { info: { name: string; }; }; } // 根据路径 user.info.name 获取类型 string type UserNameType GetApiData, user.info.name; // string参考官方文档TypeScript Utility Types 官方文档