TypeScript 高级类型编程:泛型、条件类型与类型体操实战

TypeScript 高级类型编程:泛型、条件类型与类型体操实战

Ethan
2025-05-18 发布 / 正在检测是否收录...

TypeScript 的类型系统是图灵完备的——这意味着你可以在类型层面进行"编程"。掌握高级类型不仅能提高代码的可维护性,更是编写高质量库和框架的必备技能。本文从泛型出发,逐步深入到条件类型和类型体操。

泛型的本质:类型参数化

泛型(Generics)让函数、接口、类可以接受类型参数,实现"一次定义,多处复用":

// 没有泛型:每个类型都要写一遍\nfunction firstNumber(arr: number[]): number | undefined { return arr[0]; }\nfunction firstString(arr: string[]): string | undefined { return arr[0]; }\n// 使用泛型:一个函数适用所有类型\nfunction first(arr: T[]): T | undefined { return arr[0]; }\n\nconst num = first([1, 2, 3]);    // num: number\nconst str = first(['a', 'b']);   // str: string

泛型约束:限制类型参数的范围

// 使用 extends 约束泛型\ninterface HasLength { length: number; }\nfunction logLength(arg: T): T {\n  console.log(arg.length); return arg;\n}\nlogLength('hello');     // string 有 length\nlogLength([1, 2, 3]);   // array 有 length\nlogLength(123);         // number 没有 length,编译错误\n\n// 使用 keyof 约束为对象属性的键\nfunction getProperty(obj: T, key: K): T[K] {\n  return obj[key];\n}

条件类型:类型层面的 if/else

条件类型是 TypeScript 类型系统的"控制流":

// 基本语法:T extends U ? X : Y\ntype IsString = T extends string ? 'yes' : 'no';\ntype A = IsString;  // 'yes'\ntype B = IsString;  // 'no'\n\n// 实际应用:提取类型\ntype ExtractPromise = T extends Promise ? R : T;\ntype C = ExtractPromise>;  // string\ntype D = ExtractPromise;           // number\n\n// 深层提取\ntype DeepExtractPromise = T extends Promise ? DeepExtractPromise : T;

infer 关键字:从类型中提取信息

// 提取函数返回值类型\ntype ReturnType = T extends (...args: any[]) => infer R ? R : never;\n// 提取函数参数类型\ntype FirstParam = T extends (first: infer F, ...rest: any[]) => any ? F : never;\n// 提取数组元素类型\ntype ArrayElement = T extends (infer E)[] ? E : never;

模板字面量类型:类型层面的字符串操作

type EventName = `on${Capitalize}`;\ntype ClickEvent = EventName<'click'>;  // 'onClick'\ntype ChangeEvent = EventName<'change'>; // 'onChange'\n\n// 实战:类型安全的事件系统\ntype EventMap = { click: { x: number; y: number }; change: { value: string } };\ntype EventHandlers = {\n  [K in keyof EventMap as `on${Capitalize}`]: (data: EventMap[K]) => void;\n};\n// { onClick: (data: { x: number; y: number }) => void;\n//   onChange: (data: { value: string }) => void }

映射类型与工具类型实战

interface User {\n  readonly id: number;\n  name: string;\n  age?: number;\n  email: string;\n}\n// Partial:所有属性变为可选\ntype PartialUser = Partial;\n// Required:所有属性变为必填\ntype RequiredUser = Required;\n// Pick:选取部分属性\ntype UserPreview = Pick;\n// Omit:排除部分属性\ntype UserWithoutId = Omit;\n// Record:构造对象类型\ntype PageRoute = Record;

实战:类型安全的 API 请求封装

// 定义 API 接口映射\ninterface ApiMap {\n  '/api/user': { id: number };\n  '/api/users': { page: number; size: number };\n}\ninterface ApiResultMap {\n  '/api/user': { id: number; name: string; email: string };\n  '/api/users': { total: number; list: Array<{ id: number; name: string }> };\n}\n\n// 类型安全的请求函数\nasync function request(\n  url: T, params: ApiMap[T]\n): Promise {\n  const response = await fetch(url, { method: 'POST', body: JSON.stringify(params) });\n  return response.json();\n}\n\n// 使用时获得完整的类型提示和检查\nconst user = await request('/api/user', { id: 1 }); // user.name 有自动补全

总结

TypeScript 的类型系统是一把双刃剑。用得好的类型能成为最好的文档和最可靠的守卫;用得过度的类型会成为维护的负担。掌握高级类型的关键在于:先解决实际问题,再追求类型的优雅

© 版权声明
THE END
喜欢就支持一下吧
点赞 1 分享 收藏

评论 (0)

取消

Warning: file_put_contents(/var/www/html/usr/cache/pagecache/71/719551f1b877ea7309b2cfbd2bae071f.cache): failed to open stream: No such file or directory in /var/www/html/usr/plugins/PageCache/Plugin.php on line 188