export class PLazy < ValueType > extends Promise < ValueType > { private _promise ? : Promise < ValueType > ; constructor ( private _executor ) { super ( ( resolve ) => resolve ( ) ) ; } then : Promise < ValueType > [ 'then' ] = ( onFulfilled , onRejected ) => ( this . _promise ||= new Promise ( this . _executor ) ) . then ( onFulfilled , onRejected ) ; catch : Promise < ValueType > [ 'catch' ] = ( onRejected ) => ( this . _promise ||= new Promise ( this . _executor ) ) . catch ( onRejected ) ; finally : Promise < ValueType > [ 'finally' ] = ( onFinally ) => ( this . _promise ||= new Promise ( this . _executor ) ) . finally ( onFinally ) ; } export function LazyPromise < Value > ( fn ) { return new PLazy ( ( resolve , reject ) => { try { Promise . resolve ( fn ( ) ) . then ( resolve , ( err ) => { if ( err instanceof Error && Error . captureStackTrace ) Error . captureStackTrace ( err , LazyPromise ) ; reject ( err ) ; } ) ; } catch ( err ) { if ( err instanceof Error && Error . captureStackTrace ) Error . captureStackTrace ( err , LazyPromise ) ; reject ( err ) ; } } ) ; } export interface DeferredPromise < T > { promise : Promise < T > ; resolve : ( value : T ) => void ; reject : ( reason : unknown ) => void ; value : { current ? : PromiseSettledResult < T > ; } ; } export function createDeferredPromise < T = void > ( timeoutTime ? ) { const resolve = ( value ) => { timeout != null && clearTimeout ( timeout ) ; valueRef . current ||= { status : 'fulfilled' , value } ; middlePromiseResolve ( { value , resolved : true , } ) ; } ; const reject = ( err ) => { timeout != null && clearTimeout ( timeout ) ; valueRef . current ||= { status : 'rejected' , reason : err } ; middlePromiseResolve ( { value : err , resolved : false , } ) ; } ; const valueRef = { } ; let middlePromiseResolve ! ; const MiddlePromise = new Promise < { value : unknown ; resolved : boolean ; } > ( ( resolve ) => { middlePromiseResolve = resolve ; } ) ; const promise = LazyPromise < T > ( async ( ) => { const { resolved , value } = await MiddlePromise ; if ( resolved ) return value as T ; throw value ; } ) ; let timeout ; if ( timeoutTime != null ) { timeout = setTimeout ( ( ) => { reject ( Error ( `Timed out after ${ timeoutTime }ms.` ) ) ; } , timeoutTime ) ; } return { promise , resolve , reject , value : valueRef , } ; }