type RetryActionType = 'abort' | 'retry' ; interface RetryAction < Type extends RetryActionType , Args > { type : Type ; nextArgs ? : Args ; } type NextAction < S > = RetryAction < 'abort' , undefined > | ( S extends undefined ? RetryAction < 'retry' , S > : Required < RetryAction < 'retry' , S > > ) ; export async function retry < T , S = undefined , E = unknown > ( setup ) { let result ; let currentAction ; let args = setup . initArgs ; do { try { currentAction = 'abort' ; result = await setup . action ( args ) ; } catch ( error ) { const nextAction = await setup . onFailure ( error ) ; currentAction = nextAction . type ; args = nextAction . nextArgs ; } } while ( currentAction === 'retry' ) ; return result ; }