import { isStateTreeNode , IType , TypeFlags , isType , IValidationContext , IValidationResult , typecheckInternal , typeCheckSuccess , fail , IAnyType , AnyObjectNode , BaseType , assertIsType , ExtractCSTWithSTN , devMode } from "../../internal" ; type IFunctionReturn < T > = ( ) => T ; type IOptionalValue < C , T > = C | IFunctionReturn < C | T > ; hidden export type ValidOptionalValue = string | boolean | number | null | undefined ; hidden export type ValidOptionalValues = [ ValidOptionalValue , ... ValidOptionalValue [ ] ] ; hidden internal export class OptionalValue < IT extends IAnyType , OptionalVals extends ValidOptionalValues > extends BaseType < IT [ "CreationType" ] | OptionalVals [ number ] , IT [ "SnapshotType" ] , IT [ "TypeWithoutSTN" ] > { get flags ( ) { return this . _subtype . flags | TypeFlags . Optional ; } constructor ( private readonly _subtype , private readonly _defaultValue , readonly optionalValues ) { super ( _subtype . name ) ; } describe ( ) { return this . _subtype . describe ( ) + "?" ; } instantiate ( parent , subpath , environment , initialValue ) { if ( this . optionalValues . indexOf ( initialValue ) >= 0 ) { const defaultInstanceOrSnapshot = this . getDefaultInstanceOrSnapshot ( ) ; return this . _subtype . instantiate ( parent , subpath , environment , defaultInstanceOrSnapshot ) ; } return this . _subtype . instantiate ( parent , subpath , environment , initialValue ) ; } reconcile ( current , newValue , parent , subpath ) { return this . _subtype . reconcile ( current , this . optionalValues . indexOf ( newValue ) < 0 && this . _subtype . is ( newValue ) ? newValue : this . getDefaultInstanceOrSnapshot ( ) , parent , subpath ) ; } getDefaultInstanceOrSnapshot ( ) { const defaultInstanceOrSnapshot = typeof this . _defaultValue === "function" ? ( this . _defaultValue as IFunctionReturn < this [ "C" ] | this [ "T" ] > ) ( ) : this . _defaultValue ; if ( typeof this . _defaultValue === "function" ) { typecheckInternal ( this , defaultInstanceOrSnapshot ) ; } return defaultInstanceOrSnapshot ; } isValidSnapshot ( value , context ) { if ( this . optionalValues . indexOf ( value ) >= 0 ) { return typeCheckSuccess ( ) ; } return this . _subtype . validate ( value , context ) ; } isAssignableFrom ( type ) { return this . _subtype . isAssignableFrom ( type ) ; } getSubTypes ( ) { return this . _subtype ; } } hidden export type OptionalDefaultValueOrFunction < IT extends IAnyType > = IT [ "CreationType" ] | IT [ "SnapshotType" ] | ( ( ) => ExtractCSTWithSTN < IT > ) ; hidden export interface IOptionalIType < IT extends IAnyType , OptionalVals extends ValidOptionalValues > extends IType < IT [ "CreationType" ] | OptionalVals [ number ] , IT [ "SnapshotType" ] , IT [ "TypeWithoutSTN" ] > { } function checkOptionalPreconditions < IT extends IAnyType > ( type , defaultValueOrFunction ) { if ( typeof defaultValueOrFunction !== "function" && isStateTreeNode ( defaultValueOrFunction ) ) { throw fail ( "default value cannot be an instance, pass a snapshot or a function that creates an instance/snapshot instead" ) ; } assertIsType ( type , 1 ) ; if ( devMode ( ) ) { if ( typeof defaultValueOrFunction !== "function" ) { typecheckInternal ( type , defaultValueOrFunction ) ; } } } export function optional < IT extends IAnyType > ( type , defaultValueOrFunction ) ; export function optional < IT extends IAnyType , OptionalVals extends ValidOptionalValues > ( type , defaultValueOrFunction , optionalValues ) ; param type param defaultValueOrFunction param optionalValues returns export function optional < IT extends IAnyType , OptionalVals extends ValidOptionalValues > ( type , defaultValueOrFunction , optionalValues ? ) { checkOptionalPreconditions ( type , defaultValueOrFunction ) ; return new OptionalValue ( type , defaultValueOrFunction , optionalValues ? optionalValues : undefinedAsOptionalValues ) ; } const undefinedAsOptionalValues = [ undefined ] ; template IT param type returns export function isOptionalType < IT extends IAnyType > ( type ) { return isType ( type ) && ( type . flags & TypeFlags . Optional ) > 0 ; }