import { empty , Observable , Subject , Subscriber , Subscription } from 'rxjs' ; import { catchError , shareReplay , tap } from 'rxjs/operators' ; export class SuspenseSubject < T > extends Subject < T > { private _value : T | undefined ; private _hasValue = false ; private _timeoutHandler : NodeJS . Timeout ; private _firstEmission : Promise < void > ; private _error : any = undefined ; private _innerObservable : Observable < T > ; private _warmupSubscription : Subscription ; private _innerSubscriber : Subscription ; private _resolveFirstEmission : ( ) => void ; constructor ( innerObservable , private _timeoutWindow ) { super ( ) ; this . _firstEmission = new Promise < void > ( ( resolve ) => ( this . _resolveFirstEmission = resolve ) ) ; this . _innerObservable = innerObservable . pipe ( tap ( { next : ( v ) => { this . _next ( v ) ; } , error : ( e ) => { this . _error = e ; this . _resolveFirstEmission ( ) ; } , } ) , catchError ( ( ) => empty ( ) ) , shareReplay ( 1 ) ) ; this . _warmupSubscription = this . _innerObservable . subscribe ( ) ; this . _timeoutHandler = setTimeout ( this . _reset . bind ( this ) , this . _timeoutWindow ) ; } get hasValue ( ) : boolean { return this . _hasValue || ! ! this . _error ; } get value ( ) : T { if ( this . _error ) { throw this . _error ; } else if ( ! this . hasValue ) { throw Error ( 'Can only get value if SuspenseSubject has a value' ) ; } return this . _value as T ; } get firstEmission ( ) : Promise < void > { return this . _firstEmission ; } private _next ( value ) { this . _hasValue = true ; this . _value = value ; this . _resolveFirstEmission ( ) ; } private _reset ( ) { if ( this . _warmupSubscription ) { this . _warmupSubscription . unsubscribe ( ) ; } this . _hasValue = false ; this . _value = undefined ; this . _error = undefined ; this . _firstEmission = new Promise < void > ( ( resolve ) => ( this . _resolveFirstEmission = resolve ) ) ; } _subscribe ( subscriber ) { if ( this . _timeoutHandler ) { clearTimeout ( this . _timeoutHandler ) ; } this . _innerSubscriber = this . _innerObservable . subscribe ( subscriber ) ; return this . _innerSubscriber ; } get ourError ( ) { return this . _error ; } }