前言
TypeScript 的类型系统是其最强大的特性之一。掌握高级类型技巧可以让我们写出更加类型安全的代码。本文将深入探讨条件类型、映射类型、模板字面量类型等高级特性。
条件类型
条件类型允许我们基于其他类型来推导类型:
1 2 3 4
| type IsString<T> = T extends string ? 'yes' : 'no';
type A = IsString<string>; type B = IsString<number>;
|
分布式条件类型
当条件类型作用于联合类型时,会发生分布式计算:
1 2 3 4
| type ToArray<T> = T extends any ? T[] : never;
type StrOrNumArr = ToArray<string | number>;
|
映射类型
映射类型允许我们从现有类型创建新类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| type Readonly<T> = { readonly [P in keyof T]: T[P]; };
type Partial<T> = { [P in keyof T]?: T[P]; };
interface User { name: string; age: number; }
type ReadonlyUser = Readonly<User>; type OptionalUser = Partial<User>;
|
带修饰符的映射
1 2 3 4 5 6 7 8 9
| type Writable<T> = { -readonly [P in keyof T]: T[P]; };
type Required<T> = { [P in keyof T]-?: T[P]; };
|
模板字面量类型
TypeScript 4.1 引入了模板字面量类型:
1 2 3 4 5 6 7
| type EventName = `on${Capitalize<string>}`; type CSSUnit = `${number}px` | `${number}rem` | `${number}%`;
type CSSProperties = { [K in `margin-${'top' | 'right' | 'bottom' | 'left'}`]: string | number; };
|
高级技巧组合
元组类型转换
1 2 3 4 5 6 7
| type TupleToObject<T extends readonly any[]> = { [K in T[number]]: K; };
type Tuple = ['a', 'b', 'c']; type Object = TupleToObject<Tuple>;
|
递归类型
1 2 3 4 5 6 7
| type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? T[P] extends Function ? T[P] : DeepReadonly<T[P]> : T[P]; };
|
实战案例
实现一个类型安全的 EventEmitter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| type EventMap = Record<string, any>;
class TypedEventEmitter<T extends EventMap> { private listeners: Partial<{ [K in keyof T]: Set<(payload: T[K]) => void>; }> = {};
on<K extends keyof T>(event: K, listener: (payload: T[K]) => void) { if (!this.listeners[event]) { this.listeners[event] = new Set(); } this.listeners[event]!.add(listener); }
emit<K extends keyof T>(event: K, payload: T[K]) { this.listeners[event]?.forEach(listener => listener(payload)); } }
interface Events { userLoggedIn: { userId: string; name: string }; userLoggedOut: { userId: string }; }
const emitter = new TypedEventEmitter<Events>(); emitter.on('userLoggedIn', ({ userId, name }) => { console.log(`${name} (${userId}) 登录了`); });
|
总结
TypeScript 的高级类型特性为我们提供了强大的类型推导能力。合理使用这些技巧,可以让我们的代码更加类型安全,同时保持良好的开发体验。