如何在TypeScript中为Shopify REST客户端响应动态分配类型
Shopify Node.js REST客户端的TypeScript类型封装方案
问题背景
我正在使用Shopify的Node.js REST客户端,相关请求与响应示例如下:
- 请求示例:
client.get({ path: 'orders/count.json', query: { fulfillment_status: 'unfulfilled' } })
- 错误响应示例:
{ "errors": "[API] Invalid API key or access...", "code": 2342, "statusText": "Authentication Error", "Headers": "..." }
- 成功响应示例:
{ "body": { "count": 8 }, "code": 200, "statusText": "OK", "Headers": "..." }
我希望封装该客户端,让调用时能自动获取响应的TypeScript类型,同时期望调用方式如下:
const { count, errors } = await customClient.get({ path: 'orders/count.json', query: { fulfillment_status: 'unfulfilled' } });
我已有完整的Shopify API类型文件,之前的尝试效果不佳:
const customClient = { get: async <T, K extends string>(params: GetRequestParams) => { const response = (await client.get(params)); if (response.body.errors) return { errors: response.body.errors }; // 此处无法正确关联类型与响应字段 return { [K]: response.body[K] as T }; }, }
解决方案
1. 基于Shopify API类型定义路径-响应映射
利用已有的Shopify API类型,定义路径到对应响应体类型的映射,让TypeScript能根据请求路径自动推导响应类型:
// 假设已有的Shopify API类型中包含这些响应类型 import type { OrderCountResponse, OrderResponse } from './shopify-api-types'; // 定义路径与响应体的映射 type ShopifyApiPathMap = { 'orders/count.json': OrderCountResponse; // 结构为 { count: number } 'orders.json': OrderResponse[]; // 其他API路径可继续扩展 }; // 提取所有合法的API路径类型 type ShopifyApiPath = keyof ShopifyApiPathMap; // 定义Get请求参数类型 type GetRequestParams<TPath extends ShopifyApiPath> = { path: TPath; query?: Record<string, string | number | boolean>; };
2. 封装带类型推导的get方法
通过条件类型区分成功/错误响应,同时根据路径自动推导返回的数据字段:
const customClient = { get: async <TPath extends ShopifyApiPath>(params: GetRequestParams<TPath>) => { const response = await client.get(params); // 错误响应处理:返回包含errors的对象 if ('errors' in response.body) { return { errors: response.body.errors, code: response.code, statusText: response.statusText } as const; } // 成功响应:根据路径映射提取对应数据,同时返回响应元信息 const responseBody = response.body as ShopifyApiPathMap[TPath]; // 提取响应体的唯一键(比如count、orders等) type ResponseKey = keyof typeof responseBody; const dataKey = Object.keys(responseBody)[0] as ResponseKey; return { [dataKey]: responseBody[dataKey], code: response.code, statusText: response.statusText, headers: response.Headers } as const; } };
3. 类型安全的调用示例
现在调用时无需手动传入泛型,TypeScript会自动根据路径推导返回类型:
// 调用订单统计接口,自动推导count为number类型 const result = await customClient.get({ path: 'orders/count.json', query: { fulfillment_status: 'unfulfilled' } }); if ('errors' in result) { // 错误分支:result.errors、result.code等类型都能正确推导 console.error('请求失败:', result.errors); } else { // 成功分支:result.count自动推导为number console.log('未完成订单数:', result.count); }
优化说明
- 无需手动传入泛型参数,TypeScript会根据请求的
path自动匹配对应的响应类型,避免手动传参出错。 - 通过
'errors' in result的类型守卫,TypeScript能自动区分成功/错误分支的类型,实现类型安全的分支处理。 - 如果Shopify API类型中已经包含完整的路径与响应映射,可以直接复用,无需手动定义
ShopifyApiPathMap,只需提取路径类型即可。
内容的提问来源于stack exchange,提问作者Dimitri
相关产品推荐
相关产品推荐

