You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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);
});

原理说明

  1. 泛型UrlToData会自动推断为URL字符串到对应数据类型的映射对象,示例中会被推断为:
    {
      '/users/1': { id: number; username: string },
      'test': { id: number; username: string; lastname: string }
    }
    
  2. get方法新增泛型Url,约束为UrlToData的键(即所有合法的URL),返回值的data类型直接取UrlToData[Url],实现了URL与数据类型的一一对应。
  3. 通过类型断言确保find返回的结果类型与当前URL匹配,避免编译报错。

内容的提问来源于stack exchange,提问作者Julien Abbadie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:32:47