如何基于`import * as Api from "..."`构建类型安全的API抽象?
解决方案
首先,你的ProviderApiKeys类型错误是因为用了对象映射而非联合类型筛选。下面是修正后的类型定义,以及完整的类型安全实现:
1. 修正基础类型定义
import * as Api from "./api"; // 筛选所有以"ProviderApi"结尾的API类名(联合类型) type ProviderApiKeys = Extract<keyof Api, `${string}ProviderApi`>; // 从API类名中提取前缀(比如GoogleWorkspaceProviderApi → GoogleWorkspace) type ProviderPrefix<T extends ProviderApiKeys> = T extends `${infer P}ProviderApi` ? P : never; // 所有合法的Provider名称(比如"GoogleWorkspace" | "Oauth2" | "Radius") type ValidProviderNames = ProviderPrefix<ProviderApiKeys>; // 获取指定API类的实例类型中,以"Create"结尾的方法 type ProviderCreateMethod<T extends ProviderApiKeys> = Extract< keyof InstanceType<Api[T]>, `${string}Create` >;
2. 实现类型安全的getProvider函数
先创建一个API类的映射表(手动维护一次即可,后续新增Provider只需添加一行),再实现函数:
// 映射Provider名称到对应的API类 const providerApiMap: Record<ValidProviderNames, new () => InstanceType<Api[ProviderApiKeys]>> = { GoogleWorkspace: Api.GoogleWorkspaceProviderApi, Oauth2: Api.Oauth2ProviderApi, Radius: Api.RadiusProviderApi, // 新增Provider时在这里添加对应映射 }; // 获取Provider实例并自动推断类型 function getProvider<N extends ValidProviderNames>(name: N) { const ApiClass = providerApiMap[name]; const instance = new ApiClass(); // 仅暴露以"Create"结尾的方法(可选,按需调整) type CreateMethod = ProviderCreateMethod<Extract<ProviderApiKeys, `${N}ProviderApi`>>; return instance as Pick<typeof instance, CreateMethod>; }
3. 使用方式
现在可以通过字符串安全调用,TypeScript会自动完成类型提示与校验:
// 类型安全,自动提示googleworkspaceCreate方法 const googleProvider = getProvider("GoogleWorkspace"); googleProvider.googleworkspaceCreate("123"); // 错误示例:传入不存在的Provider名称会触发编译报错 const invalidProvider = getProvider("Invalid"); // 错误示例:调用非Create方法会触发编译报错 googleProvider.someOtherMethod();
关键说明
Extract类型工具是修正never类型的核心,用于从联合类型中筛选符合字符串模式的成员。InstanceType<T>用于获取类的实例类型,从而筛选实例上的目标方法。providerApiMap只需手动维护一次,后续新增Provider仅需添加一行映射,彻底消除重复代码。- 最终实现的
getProvider既保证了类型安全,又将重复代码压缩到最低,错误会在编译阶段被提前捕获。
内容的提问来源于stack exchange,提问作者Elf Sternberg
相关产品推荐
相关产品推荐

