TypeScript的基本类型(字符串、数字、布尔值、数组、接口)是简单的。高级类型系统——条件类型、映射类型、模板字面量、判别联合——是TypeScript的能力和复杂性都存在的地方。以下是在生产代码中真正重要的模式。
判别联合
在复杂应用代码中最有用的TypeScript模式。判别联合是联合类型,其中每个成员都有一个共同的字面量属性(判别符),TypeScript可以用它来缩小类型。示例:`type Result = { status: ‘success’; data: User } | { status: ‘error’; error: string } | { status: ‘loading’ }`。当你检查`if (result.status === ‘success’)`时,TypeScript知道`result.data`存在。这种模式消除了整类运行时错误——你无法在错误结果上访问`result.data`,因为TypeScript在编译时将其设为类型错误。实际使用:API响应类型、状态机状态(Redux/Zustand)、表单验证状态,以及任何值可以具有几种不同形状的地方。穷举检查:在switch/if-else链中添加`_: never`默认情况,如果添加新的联合成员而处理程序未更新,则会出现编译错误。
映射类型和工具类型
映射类型转换现有类型的每个属性:`type Partial = { [K in keyof T]?: T[K] }`使所有属性可选。TypeScript附带内置工具类型:`Partial`、`Required`、`Readonly`、`Pick`、`Omit`、`Record`、`ReturnType`、`Parameters`。在实践中最常需要的模式:`Partial`用于PATCH端点主体,其中每个字段都是可选的;`Omit`用于不应包含敏感字段的响应类型;`ReturnType`用于推断函数的返回类型,而不重复它。自定义映射类型:`type Nullable = { [K in keyof T]: T[K] | null }`使每个属性可为空。`type DeepPartial = { [K in keyof T]?: T[K] extends object ? DeepPartial : T[K] }`递归地使所有嵌套属性可选。
模板字面量类型
模板字面量类型允许字符串类型构造:`type EventName = \`on${Capitalize}\“匹配’onClick’、’onChange’、’onFocus’。一个实际用例:`type CSSProperty = ‘margin’ | ‘padding’; type CSSDirection = ‘top’ | ‘right’ | ‘bottom’ | ‘left’; type CSSValue = \`${CSSProperty}-${CSSDirection}\“产生一个包含所有有效组合的类型(’margin-top’、’margin-right’、’padding-left’等)——TypeScript在编译时验证字符串。另一个:`type HttpMethod = ‘GET’ | ‘POST’ | ‘PUT’ | ‘DELETE’; type RouteKey = \`${HttpMethod} /${string}\“创建类型化的路由键。限制:模板字面量类型很强大,但可以产生非常大的联合类型(所有成员的笛卡尔积),这会减慢TypeScript的类型检查器——对大型枚举谨慎使用。
satisfies运算符和const断言
`satisfies`(TypeScript 4.9+):针对类型验证值,而不扩大推断类型。`const palette = { red: [255, 0, 0], green: ‘#00ff00’ } satisfies Record` ——TypeScript针对类型验证结构,但`palette.red`仍然被推断为`number[]`(未扩大为`string | number[]`),因此你保留了自动完成和特定类型推断。`as const`:将字面量值冻结为其最具体的类型。`const config = { host: ‘localhost’, port: 3000 } as const`产生类型`{ readonly host: ‘localhost’; readonly port: 3000 }` ——确切的字面量值,而不是`string`和`number`。用于配置对象、枚举类常量,以及任何你希望TypeScript将字面量值用作类型的地方。