UNPKG

@rzl-zone/utils-js

Version:

A modern, lightweight set of JavaScript utility functions with TypeScript support for everyday development, crafted to enhance code readability and maintainability.

127 lines (123 loc) 5.53 kB
/*! * ==================================================== * Rzl Utils-JS. * ---------------------------------------------------- * Version: 3.11.0. * Author: Rizalvin Dwiky. * Repository: https://github.com/rzl-zone/utils-js. * ==================================================== */ import { CustomPromiseType } from '@rzl-zone/ts-types-plus'; export { CustomPromiseType } from '@rzl-zone/ts-types-plus'; /** ------------------------------------------------------------- * * ***Utility Class: `CustomPromise`.*** * ------------------------------------------------------------- * **A strongly typed extension of the native {@link Promise | **`Promise`**}.** * 1. **Behaves exactly like a normal Promise** for `then`/`catch` * and `await` semantics. * 2. **Stores the final resolution or rejection internally** so * it can be retrieved by a custom `finish` handler. * 3. **Adds a `finish` method** which runs once after settlement * with access to both the fulfilled value *and* the rejection * reason (only one will be defined). * - **Key Differences from a Native `Promise`:** * - Every call to `then`/`catch` returns **`CustomPromise`** * again, so the `finish` method remains available on the * entire chain. * - `finish` provides a tuple-like callback: * - `val` → defined when fulfilled. * - `err` → defined when rejected. * @template Success Type of the resolved value. * @template Error Type of the rejection reason (default `unknown`). * @example * ```ts * import { CustomPromise, type CustomPromiseType } from "@rzl-zone/utils-js/promises"; * * type User = { id: number; name: string }; * type ApiError = { message: string }; * * function fetchUser(): CustomPromiseType<User, ApiError> { * return new CustomPromise<User, ApiError>((resolve, reject) => { * setTimeout( * () => * void (Math.random() > 0.5 * ? resolve({ id: 1, name: "Alice" }) * : reject({ message: "Random failure" })), * 500 * ); * }); * } * * fetchUser() * .then(user => { * console.log("SUCCESS:", user); * return user; * }) * .catch(err => { * console.error("ERROR:", err); * throw err; * }) * .finish((val, err) => { * // Runs once after settle, regardless of outcome * console.log("FINISH:", { val, err }); * }); * ``` * --- * - **Implementation Notes:** * - Uses `Object.setPrototypeOf` to preserve the prototype chain * for environments targeting ES5 or when subclassing Promise. * - Internal `_value` and `_error` are updated as soon as the * executor resolves or rejects, guaranteeing `finish` receives * the final state even when added after settlement. */ declare class CustomPromise<Success, Error = unknown> extends Promise<Success> implements CustomPromiseType<Success, Error> { private _value?; private _error?; private _finish; constructor(executor: (resolve: (v: Success) => void, reject: (e: Error) => void) => void); then<TResult1 = Success, TResult2 = never>(onfulfilled?: ((value: Success) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: Error) => TResult2 | PromiseLike<TResult2>) | null): CustomPromise<TResult1 | TResult2, Error>; catch<TResult = never>(onrejected?: ((reason: Error) => TResult | PromiseLike<TResult>) | null): CustomPromise<Success | TResult, Error>; /** * Registers a callback to be invoked **exactly once** when the * promise settles, with access to both the resolved value and * the rejection reason. * * If the promise is already settled when `finish` is called, * the callback executes immediately on the same tick. * * @param cb Callback receiving the final `(value, error)`. * @returns `this` for fluent chaining. */ finish(cb: (val?: Success, err?: Error) => void): this; } /** ------------------------------------------------------------ * * ***Utility: `delay`.*** * ------------------------------------------------------------ * **Creates a Promise-based delay that resolves after a given number * of milliseconds, optionally supports cancellation with `AbortSignal`.** * - **Behavior:** * - Validates `milliSeconds` is a non-zero, non-negative integer. * - Validates `signal` is an `AbortSignal` instance when provided. * - Cleans up event listeners and timers properly. * @param {number} [milliSeconds=1000] * The duration of the delay in milliseconds, default is `1000`. * @param {AbortSignal} [signal] * An optional `AbortSignal` that can cancel the delay. * @returns {Promise<void>} * A promise that resolves after the specified delay or * rejects with an `AbortError` if aborted. * @throws **{@link TypeError | `TypeError`}** while validates `milliSeconds` and `signal`: * - If `milliSeconds` **is not a valid** an `integer-number`, `NaN`, `negative-number`, or `≤ 0`. * - If `signal` **is not a valid** an`AbortSignal`. * @throws **{@link DOMException | `DOMException`}** if the delay is aborted using the signal, rejects with `AbortError`. * @example * // Waits for 2 seconds * await delay(2000); * * // Delay with AbortSignal * const controller = new AbortController(); * delay(5000, controller.signal).catch(err => console.log(err.name)); // "AbortError" * controller.abort(); */ declare const delay: (milliSeconds?: number, signal?: AbortSignal) => Promise<void>; export { CustomPromise, delay };