#typescript
#машинописный текст
Вопрос:
Я пытаюсь написать функцию, которая принимала бы объект и возвращала вложенную функцию, которая принимала бы обратный вызов и возвращала функцию того же типа. К сожалению, я не могу написать его таким образом, чтобы результат имел тот же тип, что и обратный вызов
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>
Ответ №1:
Просто добавьте свои обобщения в тот момент, когда вы их применяете — во внутренней функции вместо внешней функции. Таким образом, функция, которую вы получаете после применения настроек, является общей и может быть выведена на основе предоставленного вами аргумента.
type Constructor<T> = new (...args: any[]) => T
export type Settings = {
maxCalls: number
interval: number
errors: Constructor<Error>[]
}
export function withRetryDelayed({
maxCalls = 2,
interval = 100,
errors = [Error]
}: Partial<Settings> = {}) {
let calls = maxCalls
return <R, U extends any[]>(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);
// Now typeof withRetryCallback is (a: string) => Promise<string>
Комментарии:
1. Большое спасибо! Высоко ценится!