如何让TypeScript在泛型HttpServiceMock中推断数据对象的精确类型?
解决TypeScript HTTP Mock服务的精确类型推断问题
问题核心是原代码的泛型T会将所有传入的data类型合并为联合类型,导致调用get方法后,返回数据的类型是多个结构的混合,非共有的字段会被标记为可选。要实现根据URL自动推断对应数据的精确类型,需要重构泛型定义,让函数能捕捉每个URL与对应数据类型的映射关系。
重构后的代码实现
interface HttpServiceMockEntry<Url extends string, Data> { status: number; data: Data; url: Url; } export function createHttpServiceMock<UrlToData extends Record<string, unknown>>( data: Array<HttpServiceMockEntry<keyof UrlToData & string, UrlToData[keyof UrlToData]>> ) { return { get: async <Url extends keyof UrlToData>(url: Url): Promise<{ data: UrlToData[Url] }> => { const res = data.find((d) => d.url === url) as HttpServiceMockEntry<Url, UrlToData[Url]>; if (!res) { throw new Error(`No data found for url ${url as string}`); } return { data: res.data }; }, }; }
使用示例
const service = createHttpServiceMock([ { url: '/users/1', data: { id: 1, username: 'test', }, status: 200, }, { url: 'test', data: { id: 1, username: 'test', lastname: 'test', }, status: 200, }, ]); // 此时res.data的类型被精确推断为 { id: number; username: string; lastname: string } service.get('test').then((res) => { console.log(res.data.lastname); // TypeScript完全识别该字段存在 }); // 调用'/users/1'时,res.data类型是 { id: number; username: string } service.get('/users/1').then((res) => { console.log(res.data.username); });
原理说明
- 泛型
UrlToData会自动推断为URL字符串到对应数据类型的映射对象,示例中会被推断为:{ '/users/1': { id: number; username: string }, 'test': { id: number; username: string; lastname: string } } get方法新增泛型Url,约束为UrlToData的键(即所有合法的URL),返回值的data类型直接取UrlToData[Url],实现了URL与数据类型的一一对应。- 通过类型断言确保
find返回的结果类型与当前URL匹配,避免编译报错。
内容的提问来源于stack exchange,提问作者Julien Abbadie
相关产品推荐
相关产品推荐

