首页 > 解决方案 > 键入通用包装函数以充当记录器?

问题描述

我有一个包装任何函数的通用 JS 函数,这样当调用包装器时,它将执行包装的函数,记录事件(函数的输入和输出)然后返回输出,从而导致“透明“记录。我的问题是,尝试将此函数移动到 TS 并保存包装函数和输出的类型信息被证明有点复杂。

这是我目前所在的位置:

const syncLogger = <T>(f: T) => (...args: unknown[]): ReturnType<T> => {
  let value;
  try {
    value = f(...args);
    functionLogger('info', f, value, ...args); // actual logging
  } catch (error) {
    functionLogger('error', f, error.message, ...args); //actual logging
    throw error;
  }
  return value;
};

这就是它应该如何使用:

const myLoggedFunction = syncLogger(originalFunction);

主要问题在于args,我曾经用作函数输入的 n 个参数的列表:我认为无法让 TS 知道这些参数与要包装的原始函数的参数完全对应。

标签: typescriptgenericstypescript-generics

解决方案


我会在参数元组和函数的返回类型中都使用syncLogger泛型,如下所示:AR

const syncLogger = <A extends any[], R>(f: (...a: A) => R) => (
  ...args: A
): R => {
  let value;
  try {
    value = f(...args);
    functionLogger("info", f, value, ...args); // actual logging
  } catch (error) {
    functionLogger("error", f, error.message, ...args); //actual logging
    throw error;
  }
  return value;
};

这应该可以按您的预期工作:

function originalFunction(x: string, y: number): boolean {
  return (x <= y.toFixed())
}

const myLoggedFunction = syncLogger(originalFunction); // okay
// const myLoggedFunction: (x: string, y: number) => boolean

const bool = myLoggedFunction("121", 123); // info, originalFunction, true, "121", 123
console.log(bool) // true

事实上,在许多情况下,即使原始函数本身是通用的,这也可以工作,因为 TypeScript 3.4 中添加了对推断高阶函数类型的支持:

const loggingItself = syncLogger(syncLogger);
// TS3.3-: 
// const loggingItself: (...args: any[]) => (...args: any[]) => {} 
// TS3.4+: 
// const loggingItself: <A extends any[], R>(f: (...a: A) => R) => (...args: A) => R

无论如何,希望这会有所帮助。祝你好运!

链接到代码


推荐阅读