Are you struggling to create a function that takes an object and returns a nested function, which in turn accepts a callback and should return the same type of function? It seems like achieving this with the same type as the callback is posing quite a challenge.
type Constructor<T> = new (...args: any[]) => T
export type Settings = {
maxCalls: number
interval: number
errors: Constructor<Error>[]
}
export function withRetryDelayed<R, U extends any[]>({
maxCalls = 2,
interval = 100,
errors = [Error]
}: Partial<Settings> = {}): (cb: (...args: U) => Promise<R>) => (...args: U) => Promise<R> {
let calls = maxCalls
return (callback: (...args: U) => Promise<R>): (...args: U) => Promise<R> => {
const retrying = async (...args: U): Promise<R> => {
try {
return await callback(...args)
} catch (err) {
if (calls-- <= 1 || !errors.some(ErrorConstructor => err instanceof ErrorConstructor)) {
throw err
}
return interval
? new Promise(resolve => {
setTimeout(() => resolve(retrying(...args)), (maxCalls - calls) * interval)
})
: retrying(...args)
}
}
return retrying
}
}
const theX = (a: string): Promise<string> => Promise.resolve(a)
class MockError1 extends Error { }
const withRetryCallback = withRetryDelayed({
maxCalls: 10,
errors: [MockError1]
})(theX)
// typeof withRetryCallback is (...args: any[]) => Promise<unknown>