@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
TypeScript
/*!
* ====================================================
* 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 };