/**
 * TypeMatcher is a function returning true if input val matches given type T
 */ export type TypeMatcher < T > = ( val : unknown ) => val is T ; /**
 * Object fields type matchers structure
 */ export type FieldsMatcher < T > = { [ P in keyof T ] - ? : TypeMatcher < T [ P ] > ; } ; /**
 * Simple type alias to mark refined types, do not use _tag property!
 */ export type Refined < U , T > = U & { readonly __tag : T ; } ; /**
 * Type alias for errors
 */ export type Throwable = Error | Object ; /**
 * Match any of input values
 */ export function isAny ( val ) { return true ; } /**
 * Match any (unknown) input values
 */ export function isUnknown ( val ) { return true ; } /**
 * Match none of input values
 */ export function isNever ( val ) { return false ; } /**
 * Match string values
 */ export function isString ( val ) { const type = typeof val ; return type === "string" || ( type === "object" && val != null && ! Array . isArray ( val ) && Object . prototype . toString . call ( val ) === "[object String]" ) ; } /**
 * Match number values
 */ export function isNumber ( value ) { return typeof value === "number" || ( typeof value === "object" && value !== null && Object . prototype . toString . call ( value ) === "[object Number]" ) ; } /**
 * Match number values but not NaN or Infinite
 */ export function isFiniteNumber ( value ) { return isNumber ( value ) && ! isNaN ( value ) && isFinite ( value ) ; } /**
 * Match boolean values
 */ export function isBoolean ( value ) { return value === true || value === false || ( typeof value === "object" && value !== null && Object . prototype . toString . call ( value ) === "[object Boolean]" ) ; } /**
 * Match object values
 */ export function isObject ( value ) { const type = typeof value ; return value != null && ( type === "object" || type === "function" ) ; } /**
 * Check value built with given constructor function
 */ export function isInstanceOf < T > ( fnCtor ) { return function value ( val ) : val is T { return val instanceof fnCtor ; } ; } /**
 * Match input value is array of T using given matcher
 * isArrayOf(isString)([1]) => false
 * isArrayOf(isNumber)([1]) => true
 * isArrayOf(isString)(["one", 1]) => false
 */ export function isArrayOf < T > ( matcher ) { return function value ( val ) : val is Array < T > { if ( Array . isArray ( val ) ) { for ( const item of val ) { if ( ! matcher ( item ) ) { return false ; } } return true ; } return false ; } ; } /**
 * Checks value equality
 *
 * WARNING: always set type hint explicitly, otherwise - exhaustive checks will not work
 */ export function isLiteral < T extends string | number | boolean > ( expected ) { return function value ( val ) : val is T { return expected === val ; } ; } /**
 * Match null
 */ export function isNull ( val ) { return val === null ; } /**
 * Match undefined
 */ export function isUndefined ( val ) { return val === undefined ; } const isMissingF = isEither ( isNull , isUndefined ) ; /**
 * Match null | undefined
 */ export function isMissing ( val ) { return isMissingF ( val ) ; } /**
 * Match object fields by given matchers
 * hasFields({id: isNumber})({id: "aloha"}) => false
 */ export function hasFields < T > ( matcher ) { return function value ( val ) : val is T { if ( isObject ( val ) ) { for ( const pKey in matcher ) { const v = val . hasOwnProperty ( pKey ) ? ( val as any ) [ pKey ] : undefined ; if ( ! matcher [ pKey ] ( v ) ) { return false ; } } return true ; } return false ; } ; } export function hasOptionalFields < T > ( matcher ) { return function value ( val ) : val is T { if ( isObject ( val ) ) { for ( const pKey in matcher ) { const v = val . hasOwnProperty ( pKey ) ? ( val as any ) [ pKey ] : undefined ; if ( v !== undefined && ! matcher [ pKey ] ( v ) ) { return false ; } } return true ; } return false ; } ; } export type ObjectMapOf < T > = { [ K in string ] : T ; } ; export function isObjectMapOf < T > ( matcher ) { return function value ( val ) : val is ObjectMapOf < T > { if ( isObject ( val ) ) { for ( const pKey in val ) { if ( ! val . hasOwnProperty ( pKey ) || ! matcher ( ( val as any ) [ pKey ] ) ) { return false ; } } return true ; } return false ; } ; } /**
 * Given array of matchers, and array - match every value using matcher from same position
 * this is internally used for tuples
 */ function isExactArray ( matcher , val ) { if ( Array . isArray ( val ) && val . length === matcher . length ) { for ( const k in matcher ) { if ( ! matcher [ k ] ( val [ k ] ) ) { return false ; } } return true ; } return false ; } export function isTuple1 < A > ( a ) { return function value ( val ) : val is [ A ] { return isExactArray ( [ a ] , val ) ; } ; } export function isTuple2 < A , B > ( a , b ) { return function value ( val ) : val is [ A , B ] { return isExactArray ( [ a , b ] , val ) ; } ; } export function isTuple3 < A , B , C > ( a , b , c ) { return function value ( val ) : val is [ A , B , C ] { return isExactArray ( [ a , b , c ] , val ) ; } ; } export function isTuple4 < A , B , C , D > ( a , b , c , d ) { return function value ( val ) : val is [ A , B , C , D ] { return isExactArray ( [ a , b , c , d ] , val ) ; } ; } export function isTuple5 < A , B , C , D , E > ( a , b , c , d , e ) { return function value ( val ) : val is [ A , B , C , D , E ] { return isExactArray ( [ a , b , c , d , e ] , val ) ; } ; } export function isTuple6 < A , B , C , D , E , F > ( a , b , c , d , e , f ) { return function value ( val ) : val is [ A , B , C , D , E , F ] { return isExactArray ( [ a , b , c , d , e , f ] , val ) ; } ; } export function isTuple7 < A , B , C , D , E , F , G > ( a , b , c , d , e , f , g ) { return function value ( val ) : val is [ A , B , C , D , E , F , G ] { return isExactArray ( [ a , b , c , d , e , f , g ] , val ) ; } ; } export function isTuple8 < A , B , C , D , E , F , G , H > ( a , b , c , d , e , f , g , h ) { return function value ( val ) : val is [ A , B , C , D , E , F , G , H ] { return isExactArray ( [ a , b , c , d , e , f , g , h ] , val ) ; } ; } export function isTuple9 < A , B , C , D , E , F , G , H , I > ( a , b , c , d , e , f , g , h , i ) { return function value ( val ) : val is [ A , B , C , D , E , F , G , H , I ] { return isExactArray ( [ a , b , c , d , e , f , g , h , i ] , val ) ; } ; } export function isTuple10 < A , B , C , D , E , F , G , H , I , J > ( a , b , c , d , e , f , g , h , i , j ) { return function value ( val ) : val is [ A , B , C , D , E , F , G , H , I , J ] { return isExactArray ( [ a , b , c , d , e , f , g , h , i , j ] , val ) ; } ; } /**
 * Builds new matcher for types matching both: matcher1 and matcher2
 */ export function isBoth < A , B > ( matcher1 , matcher2 ) { return function value ( val ) : val is A & B { return matcher1 ( val ) && matcher2 ( val ) ; } ; } /**
 * Builds new matcher for types matching any of matcher1 or matcher2
 */ export function isEither < A , B > ( matcher1 , matcher2 ) { return function value ( val ) : val is A | B { return matcher1 ( val ) || matcher2 ( val ) ; } ; } /**
 * Builds new matcher for value which may be undefined
 */ export function isOptional < T > ( matcher ) { return isEither ( isUndefined , matcher ) ; } /**
 * Builds new matcher for value which may be null
 */ export function isNullable < T > ( matcher ) { return isEither ( isNull , matcher ) ; } /**
 * Build refined type matcher, ex:
 * const isPositive: TypeMatcher<number & Refined<"Positive">> = refined(isFiniteNumber)(_ => _ > 0, "Positive")
 * isPositive(1) === true
 * isPositive(0) === false
 * isPositive(-1) === false
 */ export function refined < U > ( m ) { return < T extends string > ( fn , tag ) : TypeMatcher < Refined < U , T > > => { const refn = fn as ( ( val : U ) => val is ( Refined < U , T > ) ) ; return ( _ ) : _ is Refined < U , T > => m ( _ ) && refn ( _ ) ; } ; } deprecated export function failWith ( err ) { return function on < T > ( matcher ) : TypeMatcher < T > { return function value ( val ) : val is T { if ( matcher ( val ) ) { return true ; } throw err ; } ; } ; }