Context
You are implementing reusable utilities that are commonly needed in modern web apps:
-
a robust retry wrapper for functions that can fail synchronously or asynchronously, and
-
a small validation framework for interdependent form inputs.
The environment is JavaScript/TypeScript. You may assume access to standard Web APIs (e.g., AbortController), and you should design APIs that are ergonomic for both browser and Node runtimes.
Part A — Retry higher-order function
Implement a higher-order utility wrapWithRetry(fn, options) that wraps a JavaScript/TypeScript function which may throw synchronously or return a rejected Promise.
Requirements:
-
Retry policies:
-
Retry once.
-
Retry N times.
-
Exponential backoff with configurable base/initial delay, factor, cap, and optional jitter.
-
Control which failures are retryable:
-
Allow specifying retryable error types and/or predicate functions (e.g., network errors, HTTP 5xx).
-
Timeouts:
-
Per-attempt timeout.
-
Overall timeout across all attempts.
-
Cancellation:
-
Support cancellation with
AbortController
/
AbortSignal
so the entire retrying operation can be aborted.
-
If the underlying function supports cancellation via
AbortSignal
, allow passing a per-attempt signal into the function.
-
Behavior and ergonomics:
-
The wrapper must handle both synchronous throws and asynchronous rejections uniformly.
-
Provide hooks to observe retries (e.g.,
onRetry
).
-
Return or throw the final error with meaningful context.
-
Deliverables:
-
Implementation in JS/TS.
-
Usage examples.
-
Discussion of edge cases: synchronous throw vs. asynchronous rejection, non-idempotent operations, retries outliving the caller, and error propagation.
Part B — Interdependent input validators
Build a small form component with three text inputs and a tiny validation framework.
Requirements:
-
A per-field validator that checks value length against configurable min/max.
-
A cross-field validator that errors when any two inputs have identical values.
-
When any input changes, revalidate other inputs as needed to keep cross-field constraints correct.
-
Describe and demonstrate:
-
State management for values, errors, and touched/dirty state.
-
Composing per-field and cross-field validators.
-
Event triggers (onChange, onBlur, onSubmit).
-
Error display and accessibility (e.g.,
aria-invalid
,
aria-describedby
).
-
Performance considerations (e.g., avoiding unnecessary revalidations, debouncing costly checks).
Provide a working example (TypeScript + React preferred) and explain your design choices and trade-offs.