Вывод типа вложенной функции на основе обратного вызова

#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. Большое спасибо! Высоко ценится!