typescript 重写错误捕获高阶函数来捕获异步错误?

j8yoct9x  于 2023-05-01  发布在  TypeScript
关注(0)|答案(3)|浏览(158)

在这里我有一个函数,它可以很好地捕捉同步错误,并在重新抛出它们之前对它们做一些事情。

function logExceptions<T extends (...args: any[]) => any>(func: T): (...funcArgs: Parameters<T>) => ReturnType<T> {
      return (...args: Parameters<T>): ReturnType<T> => {
        try {
          return func(...args);
        } catch (err) {
          console.log(func.name + " caused an error")
          throw err;
        }
      };
    }

function syncExample() { 
  throw new Error()
}

logExceptions(syncExample)();

console.log
“syncExample导致错误”
我可以重写这个函数,使其成为异步不可知的,并且也适用于异步函数吗?

async function asyncExample() { 
  throw new Error()
}
logExceptions(asyncExample)();

想要的控制台原木
“asyncExample导致错误”
真正的控制台原木
“”

eufgjt7s

eufgjt7s1#

我可以重写这个函数,使其成为异步不可知的,并且也适用于异步函数吗?
不能。虽然你可以尝试重载它并检测函数是否返回promise,但这是非常脆弱的。最好编写一个单独的函数来 Package 异步函数:

function logExceptions<T extends any[], U>(func: (...args: T) => PromiseLike<U>): (...args: T) => Promise<U> {
  return async (...args) => {
    try {
      return await func(...args);
    } catch (err) {
      console.log(func.name + " caused an error")
      throw err;
    }
  };
}
33qvvth1

33qvvth12#

同意@Bergi关于新功能的观点。
Typescript不喜欢在使用async方法时直接返回ReturnType。我想这是因为我没有指定ReturnType必须是Promise类型,但我现在已经找到了如何指定它的方法。
type ReturnType any〉= T extends(... args:any)=〉推断R?R:any获取函数类型的返回类型
异步函数或方法的返回类型必须是全局Promise类型。(1064)
通过提取Promise内部的模板并重新声明它,我发现了一个转机。

type ExtractPromiseTemplate<T> = T extends PromiseLike<infer U> ? U : T

function logExceptions<T extends (...args: any[]) => ReturnType<T>>(func: T): (...funcArgs: Parameters<T>) => Promise<ExtractPromiseTemplate<ReturnType<T>>> {
      return async (...args: Parameters<T>): Promise<ExtractPromiseTemplate<ReturnType<T>>> => {
        try {
          console.log('Will call now');
          const ret = await func(...args);

          return ret as ExtractPromiseTemplate<ReturnType<T>>;
        } catch (err) {
          console.log(func.name + " caused an error");

          throw err;
        }
      };
    }

async function asyncExample() { 
  throw new Error('Example')
}

logExceptions(asyncExample)();

调用以下代码测试返回值的有效性:

type ExtractPromiseTemplate<T> = T extends PromiseLike<infer U> ? U : T

function logExceptions<T extends (...args: any[]) => ReturnType<T>>(func: T): (...funcArgs: Parameters<T>) => Promise<ExtractPromiseTemplate<ReturnType<T>>> {
      return async (...args: Parameters<T>): Promise<ExtractPromiseTemplate<ReturnType<T>>> => {
        try {
          console.log('Will call now');
          const ret = await func(...args);

          return ret as Promise<ExtractPromiseTemplate<ReturnType<T>>>;
        } catch (err) {
          console.log(func.name + " caused an error");

          throw err;
        }
      };
    }

async function asyncExample():Promise<string> { 
  return 'a';
}

(async() => {
  const ret = await logExceptions(asyncExample)();
})();

新操场@bergi评论

goqiplq2

goqiplq23#

这可以利用Awaited

function logExceptions<T extends (...args: any[]) => any>(
  func: T
): (...funcArgs: Parameters<T>) => Promise<Awaited<ReturnType<T>>> {
  return async (...args: Parameters<T>) => {
    try {
      return await func(...args);
    } catch (err) {
      console.log(func.name + " caused an error");
      throw err;
    }
  };
}

相关问题