Use Custom Error Classes for Validation

This commit is contained in:
2026-07-23 07:56:50 +00:00
parent 7cb9a29e77
commit 205fb18785
3 changed files with 112 additions and 40 deletions
+50 -36
View File
@@ -1,4 +1,11 @@
import { ExponentialBackoffStoppedRetriesError, ExponentialBackoffMaxRetriesHitError } from './errors.ts';
import {
ExponentialBackoffStoppedRetriesError,
ExponentialBackoffMaxRetriesHitError,
ExponentialBackoffInvalidInfiniteIntegerError,
ExponentialBackoffNonIntegerError,
ExponentialBackoffNumberTooSmallError,
ExponentialBackoffNumberOutOfBoundsError,
} from './errors.ts';
/**
* Exponential backoff is a technique used to retry a function after a delay.
@@ -106,50 +113,57 @@ export class ExponentialBackoff {
* @throws An error if the options are invalid
*/
public static validateOptions(options: ExponentialBackoffOptions): void {
// Validate the max delay is a finite number not less than 0
if (!Number.isFinite(options.maxDelay)) {
throw new Error('maxDelay must be a finite number');
}
/** Validate the value is finite, throwing an {@link ExponentialBackoffInvalidInfiniteIntegerError} if the value is infinite */
const isFinite = (key: string, value: number): void => {
if (!Number.isFinite(value)) {
throw new ExponentialBackoffInvalidInfiniteIntegerError(key);
}
};
if (options.maxDelay < 0) {
throw new Error('maxDelay must be not less than 0');
}
/** Validate the value is an integer, throwing a {@link ExponentialBackoffNonIntegerError} if it is not an integer */
const isInteger = (key: string, value: number): void => {
if (!Number.isInteger(value)) {
throw new ExponentialBackoffNonIntegerError(key);
}
};
// Validate the max attempts is a finite number not less than 0
if (!Number.isFinite(options.maxAttempts)) {
throw new Error('maxAttempts must be a finite number');
}
/** Validate the value is within the bounds, throwing a {@link ExponentialBackoffNumberOutOfBoundsError} if it is not within the bounds */
const isWithinBounds = (key: string, value: number, min: number, max?: number): void => {
// If both the min and max are defined, validate the value, throwing a number out of bounds error if it is not within the bounds
if (min !== undefined && max !== undefined) {
if (value < min || value > max) {
throw new ExponentialBackoffNumberOutOfBoundsError(key, value, min, max);
}
if (options.maxAttempts < 0) {
throw new Error('maxAttempts must be not less than 0');
}
return;
}
// Validate the base delay is a finite number not less than 0
if (!Number.isFinite(options.baseDelay)) {
throw new Error('baseDelay must be a finite number');
}
// If only the min is defined, validate the value, throwing a number too small error if it is less than the min
if (value < min) {
throw new ExponentialBackoffNumberTooSmallError(key, value, min);
}
};
if (options.baseDelay < 0) {
throw new Error('baseDelay must be not less than 0');
}
// Validate the max delay
isFinite('maxDelay', options.maxDelay);
isWithinBounds('maxDelay', options.maxDelay, 0);
// Validate the growth rate is a finite number not less than 0
if (!Number.isFinite(options.growthRate)) {
throw new Error('growthRate must be a finite number');
}
// Validate the max attempts
isFinite('maxAttempts', options.maxAttempts);
isInteger('maxAttempts', options.maxAttempts);
isWithinBounds('maxAttempts', options.maxAttempts, 0);
if (options.growthRate < 0) {
throw new Error('growthRate must be not less than 0');
}
// Validate the base delay
isFinite('baseDelay', options.baseDelay);
isWithinBounds('baseDelay', options.baseDelay, 0);
// Validate the jitter is a finite number not less than 0 or greater than 1
if (!Number.isFinite(options.jitter)) {
throw new Error('jitter must be a finite number');
}
// Validate the growth rate
isFinite('growthRate', options.growthRate);
isWithinBounds('growthRate', options.growthRate, 0);
if (options.jitter < 0 || options.jitter > 1) {
throw new Error('jitter must be not less than 0 or greater than 1');
}
// Validate the jitter
isFinite('jitter', options.jitter);
isWithinBounds('jitter', options.jitter, 0, 1);
}
/**