
超越基础 TypeScript
TypeScript 的类型系统是图灵完备的。这些高级模式让你能够在类型层面编码复杂的约束。

条件类型
// 基础条件类型
type IsString<T> = T extends string ? true : false
type A = IsString<string> // true
type B = IsString<number> // false
// 提取类型
type Unwrap<T> = T extends Promise<infer U> ? U : T
type UnwrapArray<T> = T extends Array<infer U> ? U : T
type X = Unwrap<Promise<string>> // string
type Y = UnwrapArray<number[]> // number
// 递归条件类型
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
}
type Config = DeepReadonly<{
server: { port: number; host: string }
db: { url: string; poolSize: number }
}>
// config.server.port = 3000 // Error! readonly
映射类型
// 标准工具类型(来自 lib.d.ts)—— 为学习而复制
type MyPartial<T> = { [K in keyof T]?: T[K] }
type MyRequired<T> = { [K in keyof T]-?: T[K] } // -? 移除可选性
type MyReadonly<T> = { readonly [K in keyof T]: T[K] }
type MyPick<T, K extends keyof T> = { [P in K]: T[P] }
// 高级:转换值类型
type Stringify<T> = { [K in keyof T]: string }
type Nullable<T> = { [K in keyof T]: T[K] | null }
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
}
interface User { id: number; name: string }
type UserGetters = Getters<User>
// { getId: () => number; getName: () => string }
模板字面量类型
type EventName<T extends string> = `on${Capitalize<T>}`
type Events = EventName<'click' | 'hover' | 'focus'>
// "onClick" | "onHover" | "onFocus"
// 深层键路径
type Paths<T, Prefix extends string = ''> = {
[K in keyof T & string]:
T[K] extends object
? Paths<T[K], `${Prefix}${K}.`>
: `${Prefix}${K}`
}[keyof T & string]
type Config = { server: { port: number; host: string }; debug: boolean }
type ConfigPaths = Paths<Config> // "server.port" | "server.host" | "debug"
可辨识联合
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E }
function divide(a: number, b: number): Result<number, string> {
if (b === 0) return { success: false, error: 'Division by zero' }
return { success: true, data: a / b }
}
const result = divide(10, 2)
if (result.success) {
console.log(result.data) // TypeScript 知道这是 number
} else {
console.log(result.error) // TypeScript 知道这是 string
}
// 更强大:带缩窄的标签联合
type Action =
| { type: 'INCREMENT'; amount: number }
| { type: 'DECREMENT'; amount: number }
| { type: 'RESET' }
function reducer(state: number, action: Action): number {
switch (action.type) {
case 'INCREMENT': return state + action.amount // amount 可用
case 'DECREMENT': return state - action.amount // amount 可用
case 'RESET': return 0 // 无 amount
}
}
infer 关键字
// 提取返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never
// 提取第一个参数
type FirstArg<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never
// 提取 Promise 值
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T
// 提取组件 props (React)
type PropsOf<T> = T extends React.ComponentType<infer P> ? P : never
// 推断元组元素
type Head<T extends any[]> = T extends [infer H, ...any[]] ? H : never
type Tail<T extends any[]> = T extends [any, ...infer T] ? T : never
type H = Head<[1, 2, 3]> // 1
type T = Tail<[1, 2, 3]> // [2, 3]
带类型的构建器模式
type RequiredKeys<T> = {
[K in keyof T]: undefined extends T[K] ? never : K
}[keyof T]
class QueryBuilder<T extends Record<string, any>, Selected extends keyof T = never> {
private selectedFields: (keyof T)[] = []
private conditions: string[] = []
select<K extends keyof T>(...fields: K[]): QueryBuilder<T, Selected | K> {
this.selectedFields.push(...fields)
return this as any
}
where(condition: string): this {
this.conditions.push(condition)
return this
}
build(): string {
return `SELECT ${this.selectedFields.join(', ')} WHERE ${this.conditions.join(' AND ')}`
}
}
const query = new QueryBuilder<User>()
.select('id', 'name')
.where('active = true')
.build()
类型安全的事件发射器
type EventMap = Record<string, any[]>
class TypedEventEmitter<Events extends EventMap> {
private listeners = new Map<keyof Events, Function[]>()
on<K extends keyof Events>(event: K, listener: (...args: Events[K]) => void): this {
const existing = this.listeners.get(event) ?? []
this.listeners.set(event, [...existing, listener])
return this
}
emit<K extends keyof Events>(event: K, ...args: Events[K]): void {
this.listeners.get(event)?.forEach(listener => listener(...args))
}
}
type AppEvents = {
userCreated: [user: User]
orderPlaced: [order: Order, userId: string]
error: [message: string, code: number]
}
const emitter = new TypedEventEmitter<AppEvents>()
emitter.on('userCreated', (user) => console.log(user.name)) // user 是 User 类型
emitter.emit('orderPlaced', order, '123')