import { isFunction } from "@esfx/internal-guards" ; type LazyFactoryState < T > = { state : "factory" ; factory : ( ... args : any ) => T ; args : any [ ] | undefined ; } ; type LazyValueState < T > = { state : "value" ; value : T ; } ; type LazyResolvingState = { state : "resolving" ; } ; type LazyErrorState = { state : "error" ; error : unknown ; } ; type LazyState < T > = LazyFactoryState < T > | LazyValueState < T > | LazyResolvingState | LazyErrorState ; const noop = ( ) : any => { } ; const noopFactoryState = createFactoryState ( noop , undefined ) ; const resolvingState = { state : "resolving" } ; function createFactoryState < T > ( factory , args ) { return { state : "factory" , factory , args } ; ; } function createValueState < T > ( value ) { return { state : "value" , value } ; } function createErrorState ( error ) { return { state : "error" , error } ; } export class Lazy < T > { private _state : LazyState < T > ; constructor ( factory ) { if ( ! isFunction ( factory ) ) throw new TypeError ( "Function expected: factory" ) ; this . _state = factory === noop ? noopFactoryState : createFactoryState ( factory , undefined ) ; } get hasValue ( ) { return this . _state . state === "value" ; } get value ( ) { if ( this . _state . state === "error" ) throw this . _state . error ; if ( this . _state . state === "value" ) return this . _state . value ; if ( this . _state . state === "resolving" ) { const error = new Error ( "'value' recursively references itself during its own initialization." ) ; this . _state = createErrorState ( error ) ; throw error ; } const { factory , args } = this . _state ; this . _state = resolvingState ; try { const value = args && args . length ? factory ( ... args ) : factory ( ) ; this . _state = createValueState ( value ) ; return value ; } catch ( error ) { this . _state = createErrorState ( error ) ; throw error ; } } static from < T , A extends any [ ] > ( factory , ... args ) { const lazy = new Lazy < T > ( noop ) ; lazy . _state = createFactoryState ( factory , args ) ; return lazy ; } static for < T > ( value ) { const lazy = new Lazy < T > ( noop ) ; lazy . _state = createValueState ( value ) ; return lazy ; } }