@v4fire/core
Version:
V4Fire core library
118 lines (95 loc) • 2.76 kB
text/typescript
/*!
* V4Fire Core
* https://github.com/V4Fire/Core
*
* Released under the MIT license
* https://github.com/V4Fire/Core/blob/master/LICENSE
*/
import type {
ControllablePromise,
ControllablePromiseConstructor,
CreateControllablePromiseOptions
} from 'core/promise/interface';
export * from 'core/promise/interface';
/**
* Returns true if the specified promise implements the interface of `ControllablePromise`
* @param promise
*/
export function isControllablePromise<T extends PromiseLike<any>>(promise: T): promise is ControllablePromise<T>;
/**
* Returns true if the specified object implements the interface of `ControllablePromise`
* @param obj
*/
export function isControllablePromise(obj: unknown): obj is ControllablePromise<PromiseLike<unknown>>;
export function isControllablePromise(obj: unknown): boolean {
return Object.isPromiseLike(obj) && 'resolve' in obj;
}
/**
* Creates a promise that can be resolved from the "outside"
*
* @param opts - additional options
* @typeparam T - promise constructor
*
* @example
* ```js
* const promise = createControllablePromise();
* promise.resolve(10);
* ```
*/
export function createControllablePromise<T extends ControllablePromiseConstructor>(
opts: CreateControllablePromiseOptions<T>
): ControllablePromise<T extends (new(...args: any[]) => infer R) ? R : Promise<unknown>>;
/**
* Creates a promise that can be resolved from the "outside"
*
* @param [opts] - additional options
* @typeparam T - type of the resolved promise value
*/
export function createControllablePromise<T = unknown>(
opts?: CreateControllablePromiseOptions<PromiseConstructor>
): ControllablePromise<Promise<T>>;
export function createControllablePromise(
opts: CreateControllablePromiseOptions<PromiseConstructor> = {}
): ControllablePromise {
const
Constr = opts.type ?? Promise,
args = opts.args ?? [];
let
isPending = true;
let
resolve,
reject;
const executor = (res, rej, ...args) => {
resolve = (...args) => {
isPending = false;
// eslint-disable-next-line no-useless-call
res.call(null, ...args);
};
reject = (...args) => {
isPending = false;
// eslint-disable-next-line no-useless-call
rej.call(null, ...args);
};
opts.executor?.(resolve, reject, ...args);
};
// @ts-ignore (args is an iterable)
const promise = <ControllablePromise<T>>new Constr(executor, ...args);
if (!('isPending' in promise)) {
Object.defineProperty(promise, 'isPending', {
configurable: true,
enumerable: true,
get() {
return isPending;
}
});
}
promise.resolve = (...args) => {
resolve?.(...args);
return promise;
};
promise.reject = (...args) => {
reject?.(...args);
return promise;
};
return Object.cast(promise);
}