如何为GAPI库封装函数时基于各API类型定义约束参数类型?
解决GAPI加载函数的类型范围缩小问题
你的问题出在Parameters<typeof gapi.client.load>只会提取最后一个重载函数的参数类型,而每个@types/gapi.client.<api>包都会给gapi.client.load新增一个重载定义,所以最终只有最后引入的那个API(比如你提到的Drive)的参数被识别到。要让类型包含所有已安装API的合法参数,可以通过以下方式实现:
1. 提取所有重载的参数类型
首先定义一个类型工具,提取函数的所有重载参数:
// 递归提取函数的所有重载参数类型 type AllOverloadParameters<T> = T extends (...args: infer A) => any ? A | AllOverloadParameters<Omit<T, "">> : never; // 获取gapi.client.load的所有重载参数组合 type GapiLoadArgs = AllOverloadParameters<typeof gapi.client.load>; // 提取合法的API名称联合类型 type GapiApiName = GapiLoadArgs[0]; // 提取合法的版本号联合类型 type GapiApiVersion = GapiLoadArgs[1];
2. 封装类型安全的加载函数
用上面定义的类型约束参数,同时可以通过泛型关联API类型:
import { ReplaySubject } from 'rxjs'; private loadApi<T>( api: GapiApiName, version: GapiApiVersion, observer: ReplaySubject<T> ) { gapi.client.load(api, version, () => { // 将加载后的API实例投射到观察者中 observer.next(gapi.client[api] as unknown as T); observer.complete(); }); }
3. 更精确的类型关联(可选)
如果希望自动推断对应API的具体类型,可以定义一个API映射类型,让泛型自动关联:
// 映射API名称到对应的类型 type GapiApiMap = { 'calendar': typeof gapi.client.calendar; 'drive': typeof gapi.client.drive; // 新增其他API时,在这里补充映射关系 }; private loadApi<K extends keyof GapiApiMap>( api: K, version: GapiApiVersion, observer: ReplaySubject<GapiApiMap[K]> ) { gapi.client.load(api, version, () => { observer.next(gapi.client[api] as GapiApiMap[K]); observer.complete(); }); }
这样调用时,传入'calendar',TypeScript会自动推断观察者的类型为ReplaySubject<typeof gapi.client.calendar>,无需手动指定泛型。
关键原理说明
每个@types/gapi.client.<api>包都会在gapi.client命名空间下为load函数添加一个重载,比如Calendar包添加load('calendar', 'v3', ...),Drive包添加load('drive', 'v3', ...)。但Parameters工具默认只取最后一个重载的参数,所以需要用自定义类型工具合并所有重载的参数类型,才能得到完整的合法参数集合。
内容的提问来源于stack exchange,提问作者J. Barton
相关产品推荐
相关产品推荐

