TypeScript 高级类型体操指北
从条件类型、模板字面量到类型推断,掌握让同事眼前一亮的 TS 工具类型写法。
2 分钟阅读288 字
一、概述
当基础类型不再够用时,TypeScript 提供的"类型层级"允许我们像写代码一样构造复杂类型。本文通过真实业务场景,带你从"会写工具类型"走向"能设计类型库"。
二、背景
类型体操(Type Gymnastics)不是炫技,而是把运行时约束前移到编译期的能力。当我们能为 API 定义精确的输入输出类型时,IDE 的自动补全、错误提示、重构能力都会被同步增强。
三、实战片段
3.1 条件类型与 infer
TS
type Awaited<T> = T extends Promise<infer U> ? U : T
type T0 = Awaited<Promise<string>> // string
type T1 = Awaited<number> // number
3.2 模板字面量类型
TS
type EventName<T extends string> = `on${Capitalize<T>}`
type T0 = EventName<'click'> // "onClick"
3.3 递归类型:DeepReadonly
TS
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
}
interface State {
user: { name: string; tags: string[] }
}
const s: DeepReadonly<State> = { user: { name: 'a', tags: ['x'] } }
s.user.tags.push('y') // ❌ 类型错误
3.4 工具类型组合
TS
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>
interface Config { id?: string; name: string; debug?: boolean }
type T0 = RequiredBy<Config, 'id' | 'debug'> // id 和 debug 必填
四、最佳实践
- 优先使用工具类型组合 而不是新造轮子。
- 命名即文档:
ApiResponse<T, K extends 'ok' | 'err'>优于R。 - 避免无限递归:在递归类型中加上
unknown[]/ 深度阈值守卫。 - 善用
satisfies:在保留字面量推断的同时校验结构。
TS
const config = {
api: 'https://api.example.com',
timeout: 5000
} satisfies Record<string, string | number>
五、总结
类型体操的核心是用类型表达约束,让编译器成为我们的第一位 QA。练手的最佳方式是读 TypeScript Handbook + 看 type-challenges 仓库的 PR。
文章 slug: typescript-advanced-types
最后更新: 2026-06-14
版权声明 · CC BY-NC-ND 4.0
署名-非商业性使用-禁止演绎 4.0 国际
评论
由 GitHub Discussions 驱动