You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在映射类型的子映射中筛选成员生成层级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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 05:32:47