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

TypeScript重载useFetch钩子无法推导ErrType泛型类型的问题

问题:TypeScript无法推导useFetch重载中的ErrType泛型类型

我正在实现一个带可选错误格式化器的重载useFetch钩子,错误格式化器可以返回任意类型,因此将其设为泛型类型。但TypeScript无法从formatError参数函数中推导ErrType的类型。我尝试了一个简化示例,该示例可以正常工作,却不明白useFetch为何不行,希望了解原因及解决方法。

useFetch代码实现

type UseFetchReturnType<ResponseType, ErrType> = {
  data: ResponseType | null,
  error: ErrType | null,
  loading: boolean
};

function useFecth<ResponseType>(url: string): UseFetchReturnType<ResponseType, string>;
function useFecth<
  ResponseType,
  ErrType,
>(url: string, formatError: (x: any) => ErrType): UseFetchReturnType<ResponseType, ErrType>;

function useFecth<ResponseType>(url: string, formatError?: (x: any) => unknown) {
  ...
  ...
  ...
  return {
    data,
    error,
    loading,
  };
}


const { data: numArr, error: numberErr } = useFecth<number[]>('https://url1', (x: any): number => 7);
const { data: stringVal, error: boolErr } = useFecth<string>('https://url2', (x: any): boolean => false);
const { data: stringArr, error: stringErr } = useFecth<string[]>('https://url2');

可正常工作的简化示例

// 泛型作为函数返回类型,可正常推导
function fnWrapper(): string;
function fnWrapper<T>(callback: () => T): T;
function fnWrapper(cb?: () => unknown) {
  return  cb !== undefined ? cb() : 'default value';
}

const a = fnWrapper(() => 7);
const b = fnWrapper(() => 'String val');
const c = fnWrapper();

问题原因

核心问题是重载签名与实现签名的泛型不匹配:

  • useFetch的第二个重载签名需要ResponseType和ErrType两个泛型,但实现签名只声明了ResponseType,缺失ErrType泛型参数。TypeScript处理重载时会优先匹配重载签名,但实现层的泛型缺失导致无法从formatError参数推导ErrType。
  • 对比简化示例fnWrapper:它的实现签名没有显式声明泛型,TypeScript可以直接从重载的回调参数中自动推导T类型;而useFetch的实现签名仅指定了ResponseType,无法关联到ErrType的推导逻辑。

解决方法

修改实现签名,将ErrType纳入泛型参数并设置默认值为string,同时修正函数名拼写(原代码中useFecth拼写错误,应为useFetch):

type UseFetchReturnType<ResponseType, ErrType> = {
  data: ResponseType | null,
  error: ErrType | null,
  loading: boolean
};

function useFetch<ResponseType>(url: string): UseFetchReturnType<ResponseType, string>;
function useFetch<ResponseType, ErrType>(url: string, formatError: (x: any) => ErrType): UseFetchReturnType<ResponseType, ErrType>;

// 实现签名添加ErrType泛型,并设置默认值兼容无formatError的场景
function useFetch<ResponseType, ErrType = string>(url: string, formatError?: (x: any) => ErrType) {
  // 保留原有业务逻辑
  const data: ResponseType | null = null;
  const error: ErrType | null = null;
  const loading = false;
  
  return {
    data,
    error,
    loading,
  };
}

// 现在类型推导正常工作
const { data: numArr, error: numberErr } = useFetch<number[]>('https://url1', (x: any): number => 7);
const { data: stringVal, error: boolErr } = useFetch<string>('https://url2', (x: any): boolean => false);
const { data: stringArr, error: stringErr } = useFetch<string[]>('https://url2');

说明

  • 给ErrType设置默认值string后,当不传递formatError参数时,会自动匹配第一个重载的返回类型(错误类型为string)。
  • 实现签名包含两个泛型参数,TypeScript可以从formatError的返回值中正确推导ErrType,同时兼容两种调用场景。

内容的提问来源于stack exchange,提问作者Žilvinas Vidmantas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 16:42:02