如何用TypeScript消除异步API调用类型重复,自动生成三类操作类型?
Automatically Generate CRUD Action Types in TypeScript
当然可以!TypeScript的类型系统正好能帮你解决这种重复代码的问题——不用再手动写每组的Xxx、XxxOK、XxxFail类型了。下面我一步步给你演示怎么实现:
1. 先回顾你的基础定义
首先先确认我们要基于的核心类型:
// 你的ApiActionCreator定义 export type ApiActionCreator<T extends object, Payload = object | any[] | undefined> = T & { payload: Payload, error: ErrorMessage } // 你的特殊SetCurrent类型 export interface SetCurrent { type: PeopleActionTypes.SET_CURRENT; id: string; }; // 假设你的PeopleActionTypes是字符串枚举(确保类型字符串可拼接) export enum PeopleActionTypes { GET_ALL = 'GET_ALL', GET_ONE = 'GET_ONE', ADD = 'ADD', UPDATE = 'UPDATE', REMOVE = 'REMOVE', RESET_PASSWORD = 'RESET_PASSWORD', // 成功/失败类型会自动生成,不用手动枚举 }
2. 创建通用工具类型生成单组操作
先写一个复用的工具类型,用来生成单个操作的三种状态(请求、成功、失败):
// 生成单个操作的完整状态类型集合 type GenerateApiActionSet< ActionType extends string, RequestPayload = undefined, SuccessPayload = undefined > = { // 请求发起时的Action(比如GET_ALL) Request: ApiActionCreator<{ type: ActionType }, RequestPayload>; // 请求成功的Action(自动拼接`_OK`后缀,比如GET_ALL_OK) Success: ApiActionCreator<{ type: `${ActionType}_OK` }, SuccessPayload>; // 请求失败的Action(自动拼接`_FAIL`后缀,比如GET_ALL_FAIL) Fail: ApiActionCreator<{ type: `${ActionType}_FAIL` }>; };
这里用了TypeScript的模板字符串类型,自动帮你拼接成功/失败的类型标识,完全不用手动写重复的字符串。
3. 批量生成所有操作类型
接下来有两种方式生成所有操作的类型集合:
方式一:逐个定义(适合操作不多的场景)
直接为每个业务操作调用工具类型:
// 为每个操作生成三组类型 type GetAllActions = GenerateApiActionSet<PeopleActionTypes.GET_ALL, undefined, Fetchable<Person>[]>; type GetOneActions = GenerateApiActionSet<PeopleActionTypes.GET_ONE, { id: string }, Fetchable<Person>>; type AddActions = GenerateApiActionSet<PeopleActionTypes.ADD, Fetchable<Person>, Fetchable<Person>[]>; type UpdateActions = GenerateApiActionSet<PeopleActionTypes.UPDATE, Fetchable<Person>, Fetchable<Person>[]>; type RemoveActions = GenerateApiActionSet<PeopleActionTypes.REMOVE, { id: string }>; type ResetPasswordActions = GenerateApiActionSet<PeopleActionTypes.RESET_PASSWORD, { id: string }>;
方式二:映射类型批量生成(适合操作较多的场景)
如果你的操作很多,可以用映射类型批量处理,只需要维护一个Payload映射表:
// 定义每个操作对应的请求/成功Payload类型 interface PeopleActionPayloadMap { [PeopleActionTypes.GET_ALL]: { request: undefined; success: Fetchable<Person>[]; }; [PeopleActionTypes.GET_ONE]: { request: { id: string }; success: Fetchable<Person>; }; [PeopleActionTypes.ADD]: { request: Fetchable<Person>; success: Fetchable<Person>[]; }; [PeopleActionTypes.UPDATE]: { request: Fetchable<Person>; success: Fetchable<Person>[]; }; [PeopleActionTypes.REMOVE]: { request: { id: string }; success: undefined; }; [PeopleActionTypes.RESET_PASSWORD]: { request: { id: string }; success: undefined; }; } // 用映射类型批量生成所有操作的三种状态 type GeneratedPeopleApiActions = { [K in keyof PeopleActionPayloadMap]: GenerateApiActionSet< K, PeopleActionPayloadMap[K]['request'], PeopleActionPayloadMap[K]['success'] >; };
4. 合并最终的联合类型
最后把所有生成的类型和特殊的SetCurrent合并成你需要的PeopleActionCreators:
// 方式一的合并方式 type AllApiActionCreators = | GetAllActions['Request'] | GetAllActions['Success'] | GetAllActions['Fail'] | GetOneActions['Request'] | GetOneActions['Success'] | GetOneActions['Fail'] | AddActions['Request'] | AddActions['Success'] | AddActions['Fail'] | UpdateActions['Request'] | UpdateActions['Success'] | UpdateActions['Fail'] | RemoveActions['Request'] | RemoveActions['Success'] | RemoveActions['Fail'] | ResetPasswordActions['Request'] | ResetPasswordActions['Success'] | ResetPasswordActions['Fail']; // 方式二的合并方式(更简洁) // type AllApiActionCreators = GeneratedPeopleApiActions[keyof GeneratedPeopleApiActions][keyof GenerateApiActionSet<string>]; // 最终的联合类型 export type PeopleActionCreators = AllApiActionCreators | SetCurrent;
关键优势
- 完全避免重复代码:新增操作只需要在映射表或工具类型调用里加一行,不用手动写三组类型
- 类型一致性:自动拼接的
_OK/_FAIL后缀不会出现拼写错误 - 可维护性强:所有操作的Payload类型集中管理,修改起来更方便
内容的提问来源于stack exchange,提问作者dagda1
相关产品推荐
相关产品推荐

