The Concise TypeScript Book 泛型实战指南:从参数化类型到上下文收窄 文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载本文是开源项目《The Concise TypeScript Book》TypeScript 简明指南中泛型Génériques章节的深度讲解。你将掌握用尖括号参数化类型、编写泛型类与泛型约束、利用 TypeScript 3.4 引入的高阶函数类型推断实现无点风格point-free编程以及利用上下文收窄在条件语句中安全处理泛型参数——读完即可把这套能力直接用到日常的类型安全开发中。泛型的本质为类型编写参数泛型Generics允许你创建可与多种类型一起工作的可复用组件与函数。通过泛型你可以把类型本身当作参数来使用参数化类型、函数乃至接口使它们无需在定义时显式指明具体类型就能在不同类型之上运行。在《The Concise TypeScript Book》中泛型章节排在全书第 56 节与条件类型、infer 类型推断、类型操纵等章节共同构成类型系统进阶板块。它的核心价值在于两点让代码更灵活让代码更可复用——一份实现多处复用且全程保持类型安全。泛型类型用尖括号声明类型参数定义泛型类型时使用尖括号声明类型参数。最经典的例子是identity函数——它原样返回传入的值借助泛型可以做到传入什么类型就返回什么类型function identityT(arg: T): T { return arg; } const a identity(x); // a 的类型是 x const b identity(123); // b 的类型是 123调用identity时并不需要显式写出类型参数TypeScript 会根据实参自动推断T。a被推断为字面量类型xb被推断为123。另一种常见的写法是使用ReadonlyArrayT这类内置泛型工具配合箭头函数形式const getLen T,(data: ReadonlyArrayT) data.length; const len getLen([1, 2, 3]); // 3注意这里的T,末尾带有一个逗号——这是泛型箭头函数在.tsx文件中避免与 JSX 语法产生歧义的标准写法在不涉及 JSX 的.ts文件中同样合法且推荐使用。ReadonlyArrayT是ArrayT的只读版本它保证data在函数体内不可被修改从而获得更严格的不变性保证。泛型类一份类定义多种数据类型泛型同样可以应用于类。通过在类名后声明类型参数类的成员属性、方法参数、返回值都可以引用该类型参数从而创建出能作用于不同数据类型、同时保持类型安全的可复用类定义class ContainerT { private item: T; constructor(item: T) { this.item item; } getItem(): T { return this.item; } } const numberContainer new Containernumber(123); console.log(numberContainer.getItem()); // 123 const stringContainer new Containerstring(hello); console.log(stringContainer.getItem()); // helloContainernumber与Containerstring是互不兼容的两个实例类型numberContainer的getItem()返回numberstringContainer的getItem()返回string。这正是泛型类的核心收益——结构相同、类型不同、互不串扰杜绝了把number容器当string容器误用的可能。泛型约束用 extends 限定类型参数的边界如果泛型参数不加任何限制它就是任意类型unknown级别这意味着你无法安全地访问其上的任何属性。泛型约束Generic Constraints用extends关键字解决这个问题在extends后跟一个类型或接口声明类型参数必须满足该形状。下面的例子要求T必须拥有一个类型正确的length属性const printLen T extends { length: number }(value: T): void { console.log(value.length); }; printLen(Hello); // 5 printLen([1, 2, 3]); // 3 printLen({ length: 10 }); // 10 printLen(123); // Invalid —— number 没有 length 属性编译报错约束的意义在于先建立前提再提供能力。T extends { length: number }让编译器确信value.length的访问是安全的同时仍然保留T的具体类型信息字符串、数组或自定义对象而不是退化为一个宽泛的联合类型。printLen(123)之所以非法正是因为number类型不满足{ length: number }的约束这一错误会在编译期被拦截。约束也可以指向接口或其他泛型参数例如T extends Comparable、K extends keyof T等是实现泛型工具类型的基础设施。值得注意的是在本仓库的工具配置中strict: true与noImplicitAny: true均被开启这类约束写法在严格模式下能获得完整的静态检查保障。高阶函数类型推断泛型参数在组合中传播TypeScript 3.4 RC 引入了一项重要的泛型能力高阶函数类型推断higher-order function type inference。它允许类型推断从外层泛型函数穿透到作为参数传入的泛型函数上把泛型类型参数向前传播。考虑一个经典的工具函数pipe——它把两个函数组合成一个新函数declare function pipeA extends any[], B, C( ab: (...args: A) B, bc: (b: B) C ): (...args: A) C; declare function listT(a: T): T[]; declare function boxV(x: V): { value: V }; const listBox pipe(list, box); // T(a: T) { value: T[] } const boxList pipe(box, list); // V(x: V) { value: V }[]pipe接收两个函数ab接收参数元组A返回Bbc接收B返回C组合结果是一个接收A返回C的新函数。关键点在于listBox pipe(list, box)list的T与box的V两个泛型参数被正确传播推断出listBox是T(a: T) { value: T[] }——即先list后box的完整类型boxList pipe(box, list)调换顺序后推断出V(x: V) { value: V }[]——即先box后list。这项特性让类型安全的无点风格point-free编程成为可能。无点风格是函数式编程中的常见范式组合函数时完全不显式提及中间参数只描述数据如何流经函数。在 3.4 之前这种风格在 TypeScript 中往往要牺牲类型推断精度而有了高阶函数类型推断组合过程中的每个泛型参数都能被精确保留。泛型上下文收窄在条件语句中安全地处理泛型值泛型上下文收窄Generic Contextual Narrowing是 TypeScript 编译器的机制它根据泛型参数被使用的上下文把泛型参数的具体类型收窄narrow到更精确的类型。在处理泛型类型的条件语句时这一机制尤为重要——它让typeof、in、instanceof等类型守卫type guard也能作用于泛型值上。function processT(value: T): void { if (typeof value string) { // 此处 value 被收窄为 string 类型 console.log(value.length); } else if (typeof value number) { // 此处 value 被收窄为 number 类型 console.log(value.toFixed(2)); } } process(hello); // 5 process(3.14159); // 3.14在processT内部value的类型是未定的T一旦进入typeof value string分支编译器就把value收窄为string从而允许访问.length进入typeof value number分支则收窄为number允许调用.toFixed(2)。若没有收窄机制这两个分支内的属性访问都会因为T过于宽泛而报错。上下文收窄与本书前面讲解的普通变量收窄Narrowing一脉相承但针对泛型参数做了专门适配即使T本身是未实例化的类型参数编译器也能在控制流分析control flow analysis的辅助下为每个分支建立精确的类型视图。泛型的延伸与条件类型、infer 和工具类型的配合泛型并非孤立存在它是 TypeScript 整个类型操纵体系的基石。在本书后续章节中泛型被反复用于构建更高级的类型条件类型conditional-types.md 用T extends X ? A : B的形式根据条件产出类型其中T正是泛型参数infer 关键字infer-type-inference-in-conditional-types.md 在条件类型中用infer U从依赖泛型的类型中提取出内层类型type ElementTypeT T extends (infer U)[] ? U : never; type Numbers ElementTypenumber[]; // number type Strings ElementTypestring[]; // string类型操纵与内置工具类型type-manipulation.md 展示了PartialT、ReadonlyT、RecordK, T、ReturnTypeT、NoInferT等大量基于泛型实现的内置工具类型它们的底层都是泛型参数 映射/条件/索引访问的组合。从这一章到全书第 61 节类型操纵读者可以完整见证泛型如何从简单的函数签名参数一步步演化为操纵整个类型系统的语言。当你在自己项目中编写type DeepReadonlyT ...、type UnwrapT ...这类抽象时本章介绍的约束、推断传播与上下文收窄就是它们的语法基础。在 The Concise TypeScript Book 中的定位与阅读建议《The Concise TypeScript Book》是一本免费开源的 TypeScript 简明指南其内容同时以英文根目录 book/generics.md和包括法语fr-fr/book/generics.md、简体中文zh-cn/book/generics.md在内的二十余种语言维护各语言版本统一由 website/src/config/locales.ts 中的locales表驱动其中fr-fr的语言代码为fr-FR内容结构完全对齐便于对照学习。阅读本章时建议按此路径深入先用本章的四个示例泛型类型、泛型类、泛型约束、上下文收窄建立基础认知接着阅读条件类型与 infer 类型推断理解泛型如何在类型层面计算最后通读类型操纵中的内置工具类型观察标准库如何以泛型为原料构建出Partial、Record、ReturnType等能力。如需在本地体验文中的示例仓库使用strict: true、noImplicitAny: true、目标es2022的编译配置见 tools/tsconfig.json你可以将这些代码片段放入任意开启严格模式的 TypeScript 项目中验证类型推断与收窄行为——printLen(123)与fn2这类非法调用正会在编译期被精准拦截这正是泛型赋予的类型安全价值的直观体现。赞分享文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载相关推荐The Concise TypeScript Book 泛型精读从类型参数、泛型类到约束与上下文收窄The Concise TypeScript Book 泛型精读从类型参数、泛型类到约束与上下文收窄 泛型Generics是 TypeScript 构建可文档教程《The Concise TypeScript Book》泛型深度指南从通用函数到类型约束与上下文收窄《The Concise TypeScript Book》泛型深度指南从通用函数到类型约束与上下文收窄 导读 泛型Generics是 TypeScript文档教程tambo-ai/react-ui-base 解析从 1600 行巨型组件到无样式 Headless 基础组件的抽取实践tambo ai/react ui base 解析从 1600 行巨型组件到无样式 Headless 基础组件的抽取实践 导读 本文围绕 Tambo 仓库中文档教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考