import { nanoid } from 'nanoid'; export interface ITrackedPromise extends Promise { id: string; done: boolean; value?: T; resolve: (value?: T) => void; reject: () => void; } export type ITrackedPromiseConstructor = { new( executor?: ( resolve: (value: T) => void, reject: (reason?: any) => void ) => void, initialValue?: T, ): ITrackedPromise; resolve(value: T): ITrackedPromise; resolve(): ITrackedPromise; }; export const TrackedPromise = function( this: ITrackedPromise, executor?: ConstructorParameters[0], initialValue?: T, ) { let id = nanoid(); let resolver: (value?: any) => void = () => {}; let rejector: () => void = () => {}; const promise = new Promise((resolve, reject) => { resolver = (value: T) => { promise.done = true; promise.value = value; resolve(value); }; rejector = (reason?: any) => { promise.done = true; reject(reason); }; }) as ITrackedPromise; Object.assign(promise, { id, done: false, value: initialValue, resolve: resolver, reject: rejector, }); executor?.(resolver, rejector); return promise; } as unknown as ITrackedPromiseConstructor; TrackedPromise.resolve = (value?: T) => { let promise = new TrackedPromise(() => {}); promise.done = true; promise.resolve(value); return promise; };