import { fail , BaseType , IValidationContext , IValidationResult , TypeFlags , isType , IAnyType , typeCheckSuccess , AnyObjectNode , ExtractNodeType , cannotDetermineSubtype , devMode } from "../../internal" ; class Late < IT extends IAnyType > extends BaseType < IT [ "CreationType" ] , IT [ "SnapshotType" ] , IT [ "TypeWithoutSTN" ] , ExtractNodeType < IT > > { private _subType ? : IT ; get flags ( ) { return ( this . _subType ? this . _subType . flags : 0 ) | TypeFlags . Late ; } getSubType ( mustSucceed ) ; getSubType ( mustSucceed ) ; getSubType ( mustSucceed ) { if ( ! this . _subType ) { let t = undefined ; try { t = this . _definition ( ) ; } catch ( e ) { if ( e instanceof ReferenceError ) t = undefined ; else throw e ; } if ( mustSucceed && t === undefined ) throw fail ( "Late type seems to be used too early, the definition (still) returns undefined" ) ; if ( t ) { if ( devMode ( ) && ! isType ( t ) ) throw fail ( "Failed to determine subtype, make sure types.late returns a type definition." ) ; this . _subType = t ; } } return this . _subType ; } constructor ( name , private readonly _definition ) { super ( name ) ; } instantiate ( parent , subpath , environment , initialValue ) { return this . getSubType ( true ) . instantiate ( parent , subpath , environment , initialValue ) as any ; } reconcile ( current , newValue , parent , subpath ) { return this . getSubType ( true ) . reconcile ( current , newValue , parent , subpath ) as any ; } describe ( ) { const t = this . getSubType ( false ) ; return t ? t . name : "<uknown late type>" ; } isValidSnapshot ( value , context ) { const t = this . getSubType ( false ) ; if ( ! t ) { return typeCheckSuccess ( ) ; } return t . validate ( value , context ) ; } isAssignableFrom ( type ) { const t = this . getSubType ( false ) ; return t ? t . isAssignableFrom ( type ) : false ; } getSubTypes ( ) { const subtype = this . getSubType ( false ) ; return subtype ? subtype : cannotDetermineSubtype ; } } export function late < T extends IAnyType > ( type ) ; export function late < T extends IAnyType > ( name , type ) ; param name param type returns export function late ( nameOrType , maybeType ? ) { const name = typeof nameOrType === "string" ? nameOrType : `late(${ nameOrType . toString ( ) })` ; const type = typeof nameOrType === "string" ? maybeType : nameOrType ; if ( devMode ( ) ) { if ( ! ( typeof type === "function" && type . length === 0 ) ) throw fail ( "Invalid late type, expected a function with zero arguments that returns a type, got: " + type ) ; } return new Late ( name , type ) ; } param type returns export function isLateType < IT extends IAnyType > ( type ) { return isType ( type ) && ( type . flags & TypeFlags . Late ) > 0 ; }