输入一个通用的包装函数来充当记录器?

Typing a generic wrapper function to act as a logger?

我有一个包装任何函数的通用 JS 函数,这样当包装器被调用时,它将执行包装函数,记录事件(函数的输入和输出)然后 return 输出,导致 "transparent" 记录。我的问题是尝试将此函数移动到 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知道这些参数与要包装的原始功能。

我会在参数元组 A 和函数的 return 类型 R 中使 syncLogger 通用,如下所示:

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 中添加了对 inferring higher-order function types:

的支持
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

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

Link to code