键入通用包装器函数以充当记录器?



我有一个通用的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 知道这些参数与要包装的原始函数的参数完全对应。

我会在参数元组中A和函数的返回类型RsyncLogger泛型,如下所示:

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

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

链接到代码

最新更新