TypeScript 类型体操从入门到精通
类型体操是 TypeScript 中的高级类型技巧,让类型系统发挥最大威力。
基础工具类型
infer(推断)
type First<T> = T extends (infer R)[] ? R : T;
type A = First<[1, 2, 3]>; type B = First<'hello'>;
|
ReturnType
type Fn = (a: string) => number; type R = ReturnType<Fn>;
|
Parameters
type Fn = (a: string, b: number) => boolean; type P = Parameters<Fn>[0];
|
Promise
type P = Promise<boolean>; type R = UnwrapPromise<P>;
|
type T = 'a' | 'b' | 'c'; type A = Extract<T, 'a' | 'c'>; type B = Exclude<T, 'a'>;
|
进阶技巧
条件类型
type IsString<T> = T extends string ? true : false;
type A = IsString<'hello'>; type B = IsString<123>;
|
模板字面量类型
type EventName = `on${Capitalize<string>}`;
type Click = EventName<'click'>; type Change = EventName<'change'>;
|
映射类型
type Partial<T> = { [P in keyof T]?: T[P]; };
type User = { id: number; name: string; age: number; };
type PartialUser = Partial<User>;
|
条件映射
type Readonly<T> = { readonly [P in keyof T]: T[P]; };
type ReadonlyUser = Readonly<User>;
|
拆分映射
type Flip<T> = { [P in keyof T as T[P]]: P; };
type T = { a: 'foo'; b: 'bar' }; type Flipped = Flip<T>;
|
高级实战
1. 深度 Readonly
type DeepReadonly<T> = { readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P]; };
interface User { name: string; age: number; address: { city: string; country: string; }; }
type ReadonlyUser = DeepReadonly<User>;
|
2. 函数重载类型
type Handler<T> = { [K in keyof T]: (data: T[K]) => void; };
type ApiHandlers = Handler<{ login: { username: string; password: string }; logout: void; updateUser: { id: number; data: Partial<User> }; }>;
|
3. 泛型约束
type Length<T extends { length: number }> = T['length'];
type A = Length<'abc'>; type B = Length<123>;
|
4. 递归类型
type DeepPartial<T> = T extends object ? { [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]; } : T;
type User = { name: string; age: number; address: { city: string; country: string; }; };
type PartialUser = DeepPartial<User>;
|
5. 元组类型
type Tuple<T, N extends number> = N extends 0 ? [] : [T, ...Tuple<T, N - 1>];
type A = Tuple<string, 3>; type B = Tuple<number, 5>;
|
6. Promise 包装器
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
type AsyncData = Promise<string>; type Data = Awaited<AsyncData>;
|
类型运算
1. 数组去重
type Unique<T extends any[]> = T extends [infer First, ...infer Rest] ? First extends Unique<Rest> ? Unique<Rest> : [First, ...Unique<Rest>] : T;
type UniqueArray = Unique<[1, 2, 2, 3, 4, 4, 5]>;
|
2. 字符串替换
type Replace<S, From, To> = From extends '' ? S : S extends `${infer L}${From}${infer R}` ? `${L}${To}${R}` : S;
type A = Replace<'foo bar', 'bar', 'baz'>; type B = Replace<'foo bar', 'qux', 'baz'>;
|
3. 字符串首字母大写
type Capitalize<S extends string> = S extends `${infer F}${infer R}` ? `${Uppercase<F>}${R}` : S;
type A = Capitalize<'hello'>;
|
4. 函数参数推断
type Parameters2<T> = T extends (...args: infer P) => any ? P : never;
type Fn = (a: string, b: number) => boolean; type Params = Parameters2<Fn>;
|
实战案例
1. 路由参数类型
type RouteParams = { '/users': { id: string }; '/posts': { id: string; userId: string }; '/search': { q: string; page?: number }; };
type GetRouteParam<T, K extends keyof RouteParams> = RouteParams[K];
|
2. API 响应类型
type ApiResponse<T> = { data: T; error: null; status: number; };
type PostResponse = ApiResponse<{ id: number; title: string }>;
|
3. 状态管理类型
type State = { user: { name: string; email: string; }; posts: Array<{ id: number; title: string; content: string; }>; };
type UpdateUser = Partial<State['user']>;
|
性能优化
- 避免递归过深
- 使用映射类型代替循环
- 合理使用 infer
- 类型推断与性能
最佳实践
- 保持类型清晰
- 逐步增强类型
- 使用工具类型提高复用性
- 避免过度复杂化
类型体操是 TypeScript 的精髓,能极大提升代码健壮性!