【发布时间】:2022-02-12 08:47:08
【问题描述】:
我正在尝试创建一个可以将原始观察者附加到方法的高阶函数。只要输入函数没有过载,它就可以很好地工作,但是我遇到了过载问题。我想找到一种通过高阶函数传递所有重载的方法,以便返回的函数可以像原来的一样运行。这是我目前所拥有的:
我用这样的函数构建了一个观察者,为我提供了一种简单的方法来跟踪函数使用的统计信息。
function makeWatcher() {
let _callCount = 0;
function countCall() {
_callCount = _callCount + 1;
}
function getCallCount() {
return _callCount;
}
return {
countCall,
getCallCount,
};
}
然后我有一个高阶函数,它接受一个函数和一个观察者作为输入,并返回一个与观察者交互的函数,然后运行原始函数。
// Generic type assures method signature is inferred.
function watchMethod<T extends (...args: any[]) => any>(
func: T,
watcher: Watcher
): (...funcArgs: Parameters<T>) => ReturnType<T> {
// Return a new function that has same signature as input function,
// with added watcher interaction when called
return (...args: Parameters<T>): ReturnType<T> => {
// Interact with watcher
watcher.countCall();
// execute original function and return results
const results = func(...args);
return results;
};
}
最后一步是将这些组合在一起,为我提供一个具有我可以与之交互的属性的方法,如下所示:
function buildWatchedMethod<T extends (...args: any[]) => any>(inputFunction: T) {
// get a watcher
const watcher = makeWatcher();
// set up method watching
const watchedMethod= watchMethod(inputFunction, watcher);
// list out properties that should be public
const externalProperties = {
getCallCount: watcher.getCallCount
}
// assign properties to method
return Object.assign(watchedMethod, externalProperties);
}
然后我可以将观察者添加到这样的方法中:
function method(input: string){
console.log(input);
}
const watchedMethod = buildWatchedMethod(method);
watchedMethod("Hello World"); // logs "Hello World"
watchedMethod.getCallCount(); // returns 1 - method was called once
watchedMethod("Hello again"); // logs "Hello Again"
watchedMethod.getCallCount(); // returns 2
watchedMethod.countCall(); // error - not available from outside function
这很好用,保留了函数签名,保留了类型安全 - 直到 buildWatchedMethod 被重载方法调用。它仍然有效,但被监视方法的重载并没有在整个过程中保留,这让 typescript 抱怨。
这似乎是this post 的公认答案中概述的预期行为,但有没有办法通过高阶函数携带重载签名?
这个问题最常出现的地方是当我使用重载很常见的库时。 (我在看着你,Mongoose!)我也在尽量避免嘲笑像 Sinon 这样的库,因为 a)它们有时与 typescript 一起使用会很痛苦,b)我对这个用例的需求非常小,第三派对图书馆的内容往往比我需要的多得多。
欢迎提出任何建议!
【问题讨论】:
标签: typescript