
文档教程【免费下载链接】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》类型操作章节 的深度精读。它以从既有类型派生新类型为主线系统讲解交集/联合类型、映射类型、条件类型、索引访问类型以及Awaited、Partial、Record、NoInfer等 20 个内置工具类型。读完本文你将能够熟练运用类型层面的组合—变换—提取三大手法为泛型组件、状态对象、函数签名等场景写出既灵活又安全的类型代码并理解这些工具类型背后的keyof、infer、条件分发等底层机制。一、从类型创建类型Creating Types from TypesTypeScript 的核心能力之一就是通过组合compose、操纵manipulate、变换transform既有类型来创建新类型。类型不是一堆孤立的声明而是一套可以被层层推导与派生的类型系统。本节介绍四种最基础的类型派发手段交集类型、联合类型、映射类型与条件类型。1.1 交集类型Intersection Types交集类型把多个类型合并为一个类型最终的值必须同时满足所有成员类型的约束。它用连接type A { foo: number }; type B { bar: string }; type C A B; // Intersection of A and B const obj: C { foo: 42, bar: hello };从语义上讲C表示既是A又是B的值它必须拥有foo: number且bar: string两个属性。这在组合职责切片时非常实用——例如把一个类型拆成Base与Extras两个片段再通过重新拼装。交集类型专章给出了同样直观的例子type X { a: string }; type Y { b: string }; type J X Y; // Intersection const j: J { a: a, b: b };注意与extends继承的区别交集是类型层面的合成不含运行时逻辑而interface extends用于声明合并与继承。当两个成员类型对同一属性给出互相冲突的类型如string number时交集会退化为never这一点在使用时需格外留意。1.2 联合类型Union Types|联合类型表示一个值可以是多种类型中的任意一种用|连接type Result string | number; const value1: Result hello; const value2: Result 42;联合类型非常适合表达多态取值的场景例如 API 响应的多种形态、string | number的输入参数等。与之配套的判别discriminated unions与收窄narrowing技巧详见联合类型专章及书中收窄章节。1.3 映射类型Mapped Types映射类型允许你变换既有类型的每个属性来生成一个新类型。其语法核心是[P in keyof T]先通过keyof取出T的所有键再逐一对每个键重新定义属性类型type MutableT { readonly [P in keyof T]: T[P]; }; type Person { name: string; age: number; }; type ImmutablePerson MutablePerson; // Properties become read-only上例中ImmutablePerson的每个属性都被加上了readonly修饰。需要说明的是原文档示例中的类型名Mutable与其只读化的行为命名相反映射类型专章给出了更贴切的例子——把每个属性变成其原始类型的数组type MyMappedTypeT { [P in keyof T]: T[P][]; }; type MyType { foo: string; bar: number; }; type MyNewType MyMappedTypeMyType; const x: MyNewType { foo: [hello, world], bar: [1, 2, 3], };这里T[P][]表示每个属性的类型变成以原类型为元素的数组从而让MyNewType与MyType承载相同信息、却以不同格式呈现。映射类型还支持修饰符readonly或readonly将属性置为只读、-readonly取消只读、?将属性置为可选。仓库的映射类型修饰符章节给出了三件套示例type ReadOnlyT { readonly [P in keyof T]: T[P] }; // All properties marked as read-only type MutableT { -readonly [P in keyof T]: T[P] }; // All properties marked as mutable type MyPartialT { [P in keyof T]?: T[P] }; // All properties marked as optional值得一提的是下一节要讲的Partial、Required、Readonly等内置工具类型本质上就是官方对映射类型修饰符的封装实现。1.4 条件类型Conditional Types条件类型允许你基于某个条件决定最终类型语法形如三目运算T extends U ? X : Y即若T可赋值给U则取X否则取Y。配合infer关键字还能从类型中抽取出子类型type ExtractParamT T extends (param: infer P) any ? P : never; type MyFunction (name: string) number; type ParamType ExtractParamMyFunction; // string上例中T extends (param: infer P) any表示如果T是一个函数类型就把它的第一个参数类型提取出来命名为P于是ParamType推导为string。条件类型有几个重要变体值得深入了解书中均有专章分配条件类型Distributive Conditional Types当T是裸类型参数即T extends ...而非T[] extends ...时条件会逐个分发到联合的每个成员上。见分配条件类型章节type NullableT T extends any ? T | null : never; type NumberOrBool number | boolean; type NullableNumberOrBool NullableNumberOrBool; // number | boolean | null这里number | boolean被拆开分别套上| null再合并这正是Exclude、Extract、NonNullable等工具类型得以实现的底层机制。infer类型推断infer只能在条件类型的extends分支中使用用来声明一个待推断的占位类型。见infer 章节type ElementTypeT T extends (infer U)[] ? U : never; type Numbers ElementTypenumber[]; // number type Strings ElementTypestring[]; // string它从某个元素类型的数组中反推出元素类型U是Parameters、ReturnType、Awaited等工具类型的理论基石。条件类型的通用写法与判断思路可参考条件类型专章type IsArrayT T extends any[] ? true : false; const myArray [1, 2, 3]; const myNumber 42; type IsMyArrayAnArray IsArraytypeof myArray; // Type true type IsMyNumberAnArray IsArraytypeof myNumber; // Type false二、索引访问类型Indexed Access Types索引访问类型允许你用索引语法Type[Key]直接取出另一个类型中某个属性或数组/元组中某个位置的类型语法与访问对象属性值如出一辙只不过作用在类型层面type Person { name: string; age: number; }; type AgeType Person[age]; // number对元组同样适用索引即下标type MyTuple [string, number, boolean]; type MyType MyTuple[2]; // boolean索引访问与类型索引index signature是两回事后者用于声明键未知但值类型已知的字典类型type DictionaryT { [key: string]: T; }; const myDict: Dictionarystring { a: a, b: b }; console.log(myDict[a]); // Returns a理解二者区别对阅读工具类型源码很有帮助——keyof与索引访问配合正是映射类型逐键变换的完整闭环keyof T取键集合T[P]按键取类型。三、内置工具类型Utility Types逐一精解TypeScript 内置了一批开箱即用的工具类型专门用于操纵既有类型。本节逐一展开《类型操作》章节列出的20 个最常用工具类型并补充其底层原理、使用场景与注意事项。它们大多以映射类型、条件类型与infer为基础可视为上一节组合拳的官方示例。3.1 AwaitedT递归解包 Promise构造一个类型它递归地解开 Promise 的嵌套最终得到 Promise 解析出的值类型type A AwaitedPromisestring; // stringAwaitedPromisePromisenumber也会一路解包到number。它非常适合处理async函数返回值、fetch结果等异步数据流的类型提取。3.2 PartialT全部属性变为可选把T的所有属性改为可选。底层等价于映射类型{ [P in keyof T]?: T[P] }type Person { name: string; age: number; }; type A PartialPerson; // { name?: string | undefined; age?: number | undefined; }实际效果提示PartialPerson得到的是{ name?: string; age?: number }当开启exactOptionalPropertyTypes等严格选项时注释中的| undefined是否显式出现会随编译器设置与 TS 版本略有差异但语义不变。它常用于部分更新函数入参例如updateUser(id, patch: PartialUser)。3.3 RequiredT全部属性变为必填与Partial相反把T的所有可选属性改为必填等价于{ [P in keyof T]-?: T[P] }type Person { name?: string; age?: number; }; type A RequiredPerson; // { name: string; age: number; }-?修饰符正是映射类型修饰符中取消可选的用法。3.4 ReadonlyT全部属性变为只读把T的所有属性标记为readonly赋值为只读后任何改写都会在编译期报错type Person { name: string; age: number; }; type A ReadonlyPerson; const a: A { name: Simon, age: 17 }; a.name John; // Invalid注意Readonly是浅层只读嵌套对象的属性仍然可变深层不可变需要配合递归映射类型自行实现。3.5 RecordK, T构造键值映射类型用一组键K构造出每个键的值都是类型T的对象类型type Product { name: string; price: number; }; const products: Recordstring, Product { apple: { name: Apple, price: 0.5 }, banana: { name: Banana, price: 0.25 }, }; console.log(products.apple); // { name: Apple, price: 0.5 }RecordK, T的内部实现即{ [P in K]: T }。当K是字符串字面量联合时如Recordsuccess | error, string它还能保证对象恰好拥有这些键常用于枚举到数据的映射表。3.6 PickT, K挑选指定属性从T中挑选出键K指定的属性形成新类型type Product { name: string; price: number; }; type Price PickProduct, price; // { price: number; }实现等价于{ [P in K]: T[P] }其中K extends keyof T。它是瘦身接口的利器例如下游消费方只需id与title时用PickArticle, id | title限定视图模型。3.7 OmitT, K排除指定属性与Pick相反从T中剔除键K指定的属性type Product { name: string; price: number; }; type Name OmitProduct, price; // { name: string; }Omit在较新版本中的实现是PickT, Excludekeyof T, K——先借助Exclude从键集合中排除K再用Pick挑选剩余键体现了多个工具类型的组合思想。3.8 ExcludeT, U从联合中剔除从联合类型T中剔除所有可赋值给U的成员利用条件类型分发type Union a | b | c; type MyType ExcludeUnion, a | c; // b3.9 ExtractT, U从联合中提取与Exclude相反只保留T中可赋值给U的成员type Union a | b | c; type MyType ExtractUnion, a | c; // a | cExclude/Extract常用于从事件名联合、错误码联合中过滤出子集。它们与NonNullable、ReturnType等一道属于官方文档中列出的预定义条件类型见仓库预定义条件类型章节对Exclude、Extract、NonNullable、ReturnType、Parameters、Required、Partial、Readonly的概括。3.10 NonNullableT剔除 null 与 undefined从T中排除null和undefinedtype Union a | null | undefined | b; type MyType NonNullableUnion; // a | b在从可能为空的配置/响应收敛到必有值的类型时非常常用。3.11 ParametersT提取函数参数元组提取函数类型T的参数列表以元组形式type Func (a: string, b: number) void; type MyType ParametersFunc; // [a: string, b: number]其实现依赖T extends (...args: infer P) any ? P : never——这正是第一节infer的实战形态。提取出的元组可直接用于...args展开、构造同签名函数等场景。3.12 ConstructorParametersT提取构造函数参数元组提取构造函数类型T的参数元组基于abstract new (...args: infer P) any推断class Person { constructor( public name: string, public age: number ) {} } type PersonConstructorParams ConstructorParameterstypeof Person; // [name: string, age: number] const params: PersonConstructorParams [John, 30]; const person new Person(...params); console.log(person); // Person { name: John, age: 30 }注意这里的typeof Person是类构造器这一侧的类型而不是实例类型——实例类型要用下一个工具类型InstanceType。3.13 ReturnTypeT提取函数返回类型提取函数类型T的返回值类型type Func (name: string) number; type MyType ReturnTypeFunc; // number实现为T extends (...args: any) infer R ? R : any。它让函数返回值的类型可以被独立命名与复用。3.14 InstanceTypeT提取类实例类型提取构造函数类型T所构造出的实例类型class Person { name: string; constructor(name: string) { this.name name; } sayHello() { console.log(Hello, my name is ${this.name}!); } } type PersonInstance InstanceTypetypeof Person; const person: PersonInstance new Person(John); person.sayHello(); // Hello, my name is John!配合工厂函数createT(ctor: new (...args: any[]) T): T可写出传入类、返回实例的类型安全泛型工具。3.15 ThisParameterTypeT提取 this 参数类型如果函数类型T声明了this参数则提取出该参数的类型否则得到unknowninterface Person { name: string; greet(this: Person): void; } type PersonThisType ThisParameterTypePerson[greet]; // Person注意this参数只是类型层面的占位运行时并不占用真实参数位它是约束函数调用方this上下文的手段。3.16 OmitThisParameterT剔除 this 参数从函数类型T中移除this参数得到不含this的新函数签名function capitalize(this: String) { return this[0].toUpperCase() this.substring(1).toLowerCase(); } type CapitalizeType OmitThisParametertypeof capitalize; // () stringtypeof capitalize原本是(this: String) string剔除this后变成() string从而可以安全地赋给不需要this的普通回调。3.17 ThisTypeT标记上下文 this 类型ThisTypeT本身不产生任何类型变换它只是给对象字面量打上一个上下文this类型的标记配合--noImplicitThis让对象方法体内的this获得类型提示与检查type Logger { log: (error: string) void; }; let helperFunctions: { [name: string]: Function } ThisTypeLogger { hello: function () { this.log(some error); // Valid as log is a part of this. this.update(); // Invalid }, };在上例中this.log因Logger中存在log而合法this.update则因不存在该方法而报错。该模式常见于 Vue 选项对象、配置 DSL 等以this暴露上下文 API的设计。3.18 字符串模板工具Uppercase / Lowercase / Capitalize / Uncapitalize这四个工具类型对字符串字面量类型做大小写与首字母变换全部在类型层面完成type MyType Uppercaseabc; // ABCtype MyType LowercaseABC; // abctype MyType Capitalizeabc; // Abctype MyType UncapitalizeAbc; // abc它们基于模板字面量类型实现常与as const结合用于自动生成GET | POST之类的规范化字面量联合例如type HttpMethod Uppercaseget | post。3.19 NoInferT禁止类型推断NoInferT是较新加入的工具类型专门用于在泛型函数内部阻止对某个位置的类型自动推断。先看不加NoInfer时的行为——y会参与推断导致T被收窄为a | b | c// Automatic inference of types within the scope of a generic function. function fnT extends string(x: T[], y: T) { return x.concat(y); } const r fn([a, b], c); // Type here is (a | b | c)[]加上NoInferT后y的位置不再参与推断T只由x决定于是传入c会直接报错// Example function that uses NoInfer to prevent type inference function fn2T extends string(x: T[], y: NoInferT) { return x.concat(y); } const r2 fn2([a, b], c); // Error: Type Argument of type c is not assignable to parameter of type a | b.NoInfer的价值在于收紧类型约束当你希望某个参数严格从属于其他参数推导出的类型而不希望它反过来撑大推断范围时用它显式关闭该位置的推断让编译器给出更精确的报错。四、把类型操作串成体系与书中其他章节的呼应《The Concise TypeScript Book》将类型操作的知识拆成了前后呼应的章节本文内容与它们的关系如下主题仓库章节与本文的关系交集类型intersection-types.md组合手法的第一块拼图联合类型union-type.md组合手法的第二块拼图配合收窄使用映射类型mapped-types.md、mapped-type-modifiers.mdPartial/Required/Readonly的实现基础条件类型conditional-types.md、distributive-conditional-types.md、infer-type-inference-in-conditional-types.mdExclude/Extract/Parameters/ReturnType的实现基础类型索引type-indexing.md与索引访问类型互补的字典类型写法泛型generics.md类型操作的前提T、keyof T、泛型约束extends其中泛型章节尤其值得注意类型操作的载体是泛型参数T而泛型约束T extends { length: number }与条件类型的extends判断共享同一套可赋值性规则书中还展示了泛型函数的高阶推断pipe/list/box组合保持泛型传播与泛型上下文收窄这些能力与本文的Parameters/ReturnType工具类型搭配可以写出类型完全自动推导的管道式函数库。五、实战小结何时用哪个工具类型面对一个具体的类型问题可以按意图快速定位工具类型想让属性全部可选/必填/只读PartialT、RequiredT、ReadonlyT需要深层变换时自行用映射类型加修饰符递归实现。想从对象里取一部分属性PickT, K保留指定键或OmitT, K剔除指定键。想造一个键值映射对象RecordK, T。想从联合类型里过滤成员ExcludeT, U剔除、ExtractT, U提取、NonNullableT剔除null/undefined。想从函数/类身上提取类型信息ParametersT、ReturnTypeT、ConstructorParametersT、InstanceTypeT、ThisParameterTypeT、OmitThisParameterT、AwaitedT。想约束this上下文ThisTypeT。想规范化字符串字面量Uppercase、Lowercase、Capitalize、Uncapitalize。想收紧泛型推断范围NoInferT。掌握了这些工具类型你就拥有了从既有类型派生新类型的完整工具箱。更重要的是透过本节可以看到它们并非黑盒映射类型修饰符、条件类型分发与infer推断这些底层机制让任何复杂的类型变换都能被组合出来——这正是《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 第 61 章深度解析类型操作Type Manipulation组合、变换与内置工具类型全指南The Concise TypeScript Book 第 61 章深度解析类型操作Type Manipulation组合、变换与内置工具类型全指南 类型文档教程The Concise TypeScript Book 精读联合类型Union Type从入门到实战The Concise TypeScript Book 精读联合类型Union Type从入门到实战 本文以开源项目 The Concise TypeSc文档教程百度网盘解析工具终极指南如何免费实现高速下载百度网盘解析工具终极指南如何免费实现高速下载 还在为百度网盘那令人崩溃的下载速度而烦恼吗面对几十KB的龟速下载大文件传输变得遥不可及。今天我将为你介绍一文档教程上一篇Zola 部署到 Azure Static Web AppsGitHub Actions 完整配置指南下一篇Grasscutter某动漫游戏私服服务器完整部署与构建指南从环境搭建、资源目录配置到代理转发与源码编译创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考