TypeScript基于openapi-typescript生成的paths编写类型安全的通用apiCall函数
解决方案
你的代码报错核心原因是两个:
- 函数没有声明泛型参数,
path、method、params三个参数的类型没有绑定关联,TS无法根据传入的具体路径推导对应的方法、参数、返回值类型 - 没有给类型索引加兼容判断,TS不确定所有路径方法下一定存在
parameters、responses等字段,触发索引合法性校验报错
修改后的完整代码如下:
// 原有paths定义不变 export interface paths { '/v1/some-path/:id': { get: { parameters: { query: { id: number; }; header: {}; }; responses: { /** OK */ 200: { schema: { id: number; name: string; }; }; }; }; post: { parameters: { body: { name: string; }; header: {}; }; responses: { /** OK */ 200: { schema: { id: number; name: string; }; }; }; }; }; } type Path = keyof paths; type PathMethods<P extends Path> = keyof paths[P]; // 用条件类型+infer做索引兼容,避免索引不存在的报错 type RequestParams<P extends Path, M extends PathMethods<P>> = paths[P][M] extends { parameters: infer T } ? T : never; type ResponseType<P extends Path, M extends PathMethods<P>> = paths[P][M] extends { responses: { 200: { schema: infer T } } } ? T : never; // 函数声明泛型参数,绑定三个入参的类型关联 export const apiCall = <P extends Path, M extends PathMethods<P>>( path: P, method: M, params: RequestParams<P, M> ): Promise<ResponseType<P, M>> => { const url = path; console.log('params', params); return fetch(url, { method: method as string }) as Promise<ResponseType<P, M>>; };
使用效果
调用时TS会自动做类型校验和提示:
// 调用get方法,自动校验参数必须带query.id apiCall('/v1/some-path/:id', 'get', { query: { id: 123 } }).then(res => { // res自动推导为 { id: number; name: string } 类型 console.log(res.id, res.name); }); // 调用post方法,自动校验参数必须带body.name apiCall('/v1/some-path/:id', 'post', { body: { name: "测试用户" } }).then(res => { console.log(res.id, res.name); });
内容的提问来源于stack exchange,提问作者Alejandro Urbano Alvarez
相关产品推荐
相关产品推荐

