如何在映射类型的子映射中筛选成员生成层级API类型
构建层级命名空间的API映射类型
原始API接口定义
export interface ApiMethods { "rtm.auth.getToken": { requestArgs: { frob: string; }; responseArgs: { auth: { token: string; perms: string; user: User; }; }; }; "rtm.auth.getFrob": { requestArgs: Record<string, string>; responseArgs: { frob: string; }; }; "rtm.tasks.getList": { requestArgs: { list_id?: string; filter?: string; last_sync?: string; }; responseArgs: { tasks: { list: TaskList[]; }; }; }; }
需求与问题
需要将ApiMethods中的点分隔字符串键(如"rtm.auth.getToken")解析为层级对象类型,最终生成类似{ auth: { getToken: (...), getFrob(...) }, tasks: { getList(...) } }的结构。
当前实现的ApiSurface类型能生成正确的命名空间和函数名,但所有函数被错误分配到了所有命名空间下,核心问题是内层映射未利用外层的命名空间进行精准筛选。
解决方案
1. 定义字符串拆分工具类型
先实现几个基础字符串处理类型,用于拆分键中的命名空间和方法名:
// 提取字符串第一个点之前的部分 type GetFirstSegment<T extends string> = T extends `${infer First}.${string}` ? First : T; // 提取第一个点之后的剩余部分 type GetRestSegments<T extends string> = T extends `${string}.${infer Rest}` ? Rest : never; // 提取中间的命名空间部分(如从"auth.getToken"得到"auth") type GetNamespace<T extends string> = T extends `${infer Namespace}.${string}` ? Namespace : never; // 提取最后的方法名(如从"auth.getToken"得到"getToken") type GetMethodName<T extends string> = T extends `${string}.${infer Method}` ? Method : never;
2. 构建正确的层级映射类型
利用工具类型,在外层遍历唯一命名空间,内层仅筛选对应命名空间下的API方法:
export type ApiSurface = { // 遍历所有唯一的命名空间(从ApiMethods键中提取) [Namespace in Extract<GetNamespace<GetRestSegments<keyof ApiMethods & string>>, string>]: { // 仅筛选当前命名空间下的API方法,转换为方法名作为键 [Method in Extract<keyof ApiMethods & string, `rtm.${Namespace}.${string}`> as GetMethodName<GetRestSegments<Method>>]: (args: ApiMethods[Method]["requestArgs"]) => SuccessResponse<Method>; }; };
3. 类型效果验证
最终生成的ApiSurface类型等价于:
type Result = ApiSurface; // { // auth: { // getToken: (args: { frob: string; }) => SuccessResponse<"rtm.auth.getToken">; // getFrob: (args: Record<string, string>) => SuccessResponse<"rtm.auth.getFrob">; // }; // tasks: { // getList: (args: { list_id?: string; filter?: string; last_sync?: string; }) => SuccessResponse<"rtm.tasks.getList">; // }; // }
内容的提问来源于stack exchange,提问作者Ben Wainwright
相关产品推荐
相关产品推荐

