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

TypeScript中根据入参函数同步/异步特性返回类型安全值的实现问题

解决方案

核心思路

  1. 用TS内置的Awaited工具类型简化异步返回值的提取,无需自定义SyncType
  2. 实现正确的isAsync类型守卫,运行时用函数构造函数名判断是否为async函数
  3. 由于TS目前无法自动推导函数返回的条件类型匹配性,增加类型断言绕过校验
  4. 修复原代码中MyClasss的拼写错误,修正测试用例中不合理的await merge(...)写法(merge返回的是函数,需调用后再await)

完整实现代码

class MyClass<T> {
  constructor(public data: T) {}
}

/**
 * 异步函数类型守卫
 * @param func 待判断的函数
 */
function isAsync<P extends any[], R>(func: (...args: P) => R): func is (...args: P) => Promise<Awaited<R>> {
  return func.constructor.name === 'AsyncFunction';
  // 若需兼容非async声明但返回Promise的函数,可在业务场景允许的前提下补充运行时判断逻辑
}

/**
 * 将指定函数的返回值包装为MyClass实例
 * @param func 待包装的原函数
 */
function merge<P extends any[], R>(func: (...args: P) => R)
  : (...args: P) => R extends Promise<infer A> ? Promise<MyClass<A>> : MyClass<R>
{
  if (isAsync(func)) {
    return (async (...args: P) => {
      const value = await func(...args);
      return new MyClass(value);
    // 增加类型断言匹配返回的条件类型
    }) as ReturnType<typeof merge<P, R>>;
  }

  return ((...args: P) => {
    const value = func(...args);
    return new MyClass(value);
  }) as ReturnType<typeof merge<P, R>>;
}

测试验证

(async() => {
  // 异步函数测试
  const asyncMergeFn = merge(async (value: string) => value === 'test' ? 1 : 0);
  // asyncMergeFn类型:(value: string) => Promise<MyClass<number>>
  const asyncRes = await asyncMergeFn('test');
  // asyncRes类型:MyClass<number>,值为MyClass { data: 1 }

  // 同步函数测试
  const syncMergeFn = merge((value: string) => value === 'test' ? 1 : 0);
  // syncMergeFn类型:(value: string) => MyClass<number>
  const syncRes = syncMergeFn('test');
  // syncRes类型:MyClass<number>,值为MyClass { data: 1 }

  // 直接调用测试
  const directAsyncRes = await merge(async (value: string) => value === 'test' ? 1 : 0)('test');
  // directAsyncRes类型:MyClass<number>
  const directSyncRes = merge((value: string) => value === 'test' ? 1 : 0)('test');
  // directSyncRes类型:MyClass<number>
})();

扩展说明

如果你的业务场景需要支持所有返回Promise的非async声明函数,只需修改isAsync的运行时判断逻辑即可,TS的类型系统已经能通过泛型推导识别返回Promise的函数,类型守卫可以正常工作。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 22:06:05