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

TypeScript泛型错误处理包装函数返回类型兼容问题:如何实现Promise与非Promise返回值的自动推断?

解决TypeScript泛型错误处理函数的返回类型推断问题

这个问题的核心是你的泛型函数无法自动区分同步和异步回调的返回类型,导致当回调返回Promise时,TypeScript无法确认返回的Promise是否符合泛型R的约束。下面提供两种优雅的解决方案:

方案一:使用条件类型明确返回类型

通过条件类型让TypeScript根据回调的返回值自动推断函数的返回类型,同时修正类型断言以消除报错:

// 假设handleError是你已定义的错误处理函数
function handleError(error: unknown, action: string) {
  console.error(`Error occurred during ${action}:`, error);
}

export function withErrorHandler<R>(
  action: string,
  callback: () => R
): R extends Promise<infer T> ? Promise<T> : R {
  // 更健壮的Promise类型判断(兼容跨iframe场景)
  function isPromise<X>(value: unknown): value is Promise<X> {
    return (
      typeof value === 'object' &&
      value !== null &&
      'then' in value &&
      typeof (value as Promise<X>).then === 'function'
    );
  }

  try {
    const result = callback();
    if (isPromise(result)) {
      // 用类型断言告诉TS这里返回的是Promise类型,符合条件类型的分支
      return result.catch(error => {
        handleError(error, action);
        throw error; // 继续抛出错误,让调用方可以捕获
      }) as R extends Promise<infer T> ? Promise<T> : never;
    }
    return result;
  } catch (error) {
    handleError(error, action);
    throw error;
  }
}

方案二:使用函数重载(更直观)

通过重载定义两种场景的输入输出类型,让TypeScript更清晰地推断返回值:

function handleError(error: unknown, action: string) {
  console.error(`Error occurred during ${action}:`, error);
}

// 重载1:同步回调,返回原类型
export function withErrorHandler<R>(action: string, callback: () => R): R;
// 重载2:异步回调,返回Promise类型
export function withErrorHandler<R>(action: string, callback: () => Promise<R>): Promise<R>;

// 通用实现
export function withErrorHandler<R>(
  action: string,
  callback: () => R | Promise<R>
): R | Promise<R> {
  function isPromise<X>(value: unknown): value is Promise<X> {
    return (
      typeof value === 'object' &&
      value !== null &&
      'then' in value &&
      typeof (value as Promise<X>).then === 'function'
    );
  }

  try {
    const result = callback();
    if (isPromise(result)) {
      return result.catch(error => {
        handleError(error, action);
        throw error;
      });
    }
    return result;
  } catch (error) {
    handleError(error, action);
    throw error;
  }
}

为什么原来的代码会报错?

你的原始代码中,泛型R被定义为回调的返回类型,但当回调返回Promise时,你返回的是result.catch(...)(一个Promise),而TypeScript无法确保R一定是Promise类型——因为R可以被实例化为任意类型(比如字符串、数字),这就导致了类型不匹配的报错。

通过条件类型或函数重载,我们明确告诉TypeScript:

  • 如果回调返回的是Promise,函数就返回对应的Promise类型
  • 如果回调返回的是同步值,函数就返回原类型

这样TypeScript就能正确推断返回值类型,同时保留错误处理的逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 09:38:13