TypeScript 的类型系统是图灵完备的——这意味着你可以在类型层面表达几乎任何逻辑。虽然"类型体操"常被戏称为过度工程,但在实际项目中合理运用高级类型,可显著提升代码的类型安全性和可维护性,在编译期就消除大量潜在 Bug。
条件类型:类型的 if/else
条件类型是 TypeScript 类型系统中最强大的工具之一,语法为 T extends U ? X : Y。实际应用场景:
// 提取 Promise 的返回值类型
type Awaited<T> = T extends Promise<infer U> ? U : T
// 提取数组元素类型
type ElementOf<T> = T extends (infer U)[] ? U : never
// 提取函数返回值类型(TypeScript 内置了 ReturnType)
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never
// 深层 Readonly
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
}
模板字面量类型:类型安全的字符串
TypeScript 4.1 引入的模板字面量类型将字符串处理能力带入了类型系统:
// 类型安全的事件名称
type Module = 'user' | 'order' | 'product'
type Action = 'created' | 'updated' | 'deleted'
type AppEvent = `${Module}:${Action}`
// "user:created" | "user:updated" | ... | "product:deleted"
// 类型安全的路由参数
type Route = `/api/${string}/${number}`
// 匹配 /api/users/123 但不匹配 /api/users/abc
实用高级技巧
satisfies 关键字:TypeScript 4.9 引入的 satisfies 既能校验类型又能保留字面量推断,是替代类型注解的更好选择。
Branded Types(品牌类型):防止基本类型的意外混淆——将 UserId、OrderId、ProductId 编译期区分为不同"品牌",即使它们运行时都是 string。
Discriminated Unions(可辨识联合):通过共享的 discriminant 属性(如 kind: 'success' | 'error' | 'loading'),让 TypeScript 能够自动收窄联合类型,配合 switch-case 实现穷尽性检查——新增状态时编译器会自动报错提醒遗漏的分支。