Collection of functions to perform logic
yarn add @typed/logic
# or
npm install --save @typed/logic
All functions are curried!
export type Conditional<A, B> = [Predicate<A>, (value: A) => B]
Returns true
if predicate function returns true
for all values in a List
.
See the code
export const all = curry2(__all)
function __all<A>(predicate: Predicate<A>, list: List<A>): boolean {
for (let i = 0; i < list.length; ++i) if (not(predicate(list[i]))) return false
return true
}
Returns true if all predicates return true.
See the code
export const allPass: AllPass = curry2(__allPass)
export type AllPass = {
<A>(predicates: List<Predicate<A>>, value: A): boolean
<A>(predicates: List<Predicate<A>>): Predicate<A>
}
function __allPass<A>(predicates: List<Predicate<A>>, value: A): boolean {
const predicateCount = predicates.length
for (let i = 0; i < predicateCount; ++i) if (not(predicates[i](value))) return false
return true
}
Applies &&
between two predicate functions.
See the code
export const and: And = curry3(__and)
export type And = {
<A>(predicate1: Predicate<A>, predicate2: Predicate<A>, value: A): boolean
<A>(predicate1: Predicate<A>, predicate2: Predicate<A>): Predicate<A>
<A>(predicate1: Predicate<A>): {
(predicate2: Predicate<A>, value: A): boolean
(predicate2: Predicate<A>): Predicate<A>
}
}
function __and<A>(predicate1: Predicate<A>, predicate2: Predicate<A>, value: A): boolean {
return predicate1(value) && predicate2(value)
}
Returns true
if predicate function returns true
for any value contained
in a List
.
See the code
export const any: Any = curry2(__any)
function __any<A>(predicate: Predicate<A>, list: List<A>): boolean {
for (let i = 0; i < list.length; ++i) if (predicate(list[i])) return true
return false
}
Returns true if any predicates returns true, false otherwise.
See the code
export const anyPass: AnyPass = curry2(__anyPass)
export type AnyPass = {
<A>(predicates: List<Predicate<A>>, value: A): boolean
<A>(predicates: List<Predicate<A>>): (value: A) => boolean
}
function __anyPass<A>(predicates: List<Predicate<A>>, value: A): boolean {
for (const predicate of Array.from(predicates)) if (predicate(value)) return true
return false
}
Returns the value of an applied Conditional
. If no Conditional
is matched
then Nothing
is returned.
See the code
export const cond: Cond = curry2(__cond)
function __cond<A, B>(conditionals: List<Conditional<A, B>>, value: A): Maybe<B> {
const itemCount = conditionals.length
for (let i = 0; i < itemCount; ++i) {
const [predicate, f] = conditionals[i]
if (predicate(value)) return Maybe.of(f(value))
}
return Nothing
}
Checks if two values are equal.
See the code
export const equals: Equals = curry2(function equals<A>(x: A, y: A): boolean {
return isEqual(x, y, [], [])
})
function isEqual(a: any, b: any, stackA: Array<any>, stackB: Array<any>): boolean {
if (a === b) return true
if (typeOf(a) !== typeOf(b)) return false
// tslint:disable-next-line
if (a == null || b == null) return false
switch (typeOf(a)) {
case 'Arguments':
case 'Array':
case 'Object':
if (typeof a.constructor === 'function' && functionName(a.constructor) === 'Promise')
return a === b
break
case 'Boolean':
case 'Number':
case 'String':
if (!(typeof a === typeof b && a.valueOf() === b.valueOf())) return false
break
case 'Date':
if (a.valueOf() !== b.valueOf()) return false
break
case 'Error':
return a.name === b.name && a.message === b.message
case 'RegExp':
if (
!(
a.source === b.source &&
a.global === b.global &&
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline &&
a.sticky === b.sticky &&
a.unicode === b.unicode
)
) {
return false
}
break
case 'Map':
case 'Set':
if (!isEqual(Array.from(a.entries()), Array.from(b.entries()), stackA, stackB)) return false
break
case 'Int8Array':
case 'Uint8Array':
case 'Uint8ClampedArray':
case 'Int16Array':
case 'Uint16Array':
case 'Int32Array':
case 'Uint32Array':
case 'Float32Array':
case 'Float64Array':
break
case 'ArrayBuffer':
break
default:
// Values of other types are only equal if identical.
return false
}
const keysA = Object.keys(a)
if (keysA.length !== Object.keys(b).length) return false
let idx = stackA.length - 1
while (idx >= 0) {
if (stackA[idx] === a) return stackB[idx] === b
idx -= 1
}
stackA.push(a)
stackB.push(b)
idx = keysA.length - 1
while (idx >= 0) {
const key = keysA[idx]
if (!(Object.prototype.hasOwnProperty.call(b, key) && isEqual(b[key], a[key], stackA, stackB)))
return false
idx -= 1
}
stackA.pop()
stackB.pop()
return true
}
Returns the name of a function.
See the code
export function functionName(fn: Function): string {
if (fn.name) return fn.name
const [, name] = String(fn).match(FUNCTION_NAME_REGEX) || DEFAULT_MATCH
return name
}
Applies \>
to 2 values.
See the code
export const greaterThan: GreaterThan = curry2(<A>(right: A, left: A) => left > right)
export type GreaterThan = {
<A>(right: A, left: A): boolean
<A>(right: A): (left: A) => boolean
}
Applies \>=
to 2 values.
See the code
export const greaterThanOrEqual: GreaterThanOrEqual = curry2(
<A>(right: A, left: A) => left >= right
)
export type GreaterThanOrEqual = {
<A>(right: A, left: A): boolean
<A>(right: A): (left: A) => boolean
}
Function for handling if/Else statements.
See the code
export const ifElse: IfElseArity4 = curry4(__ifElse)
function __ifElse<A, B>(
ifF: (value: A) => boolean,
thenF: (value: A) => B,
elseF: (value: A) => B,
value: A
): B {
return ifF(value) ? thenF(value) : elseF(value)
}
Returns true if given value is an Array.
See the code
export function isArray<A = any>(x: any): x is Array<A> {
return Array.isArray(x)
}
Returns true if a value is an Iterable.
See the code
export function isIterable<A>(x: any): x is Iterable<A> {
return x && typeof x[Symbol.iterator] === 'function' && isIterator(x[Symbol.iterator]())
}
Returns true if value is an iterator.
See the code
export function isIterator<A>(x: any): x is Iterator<A> {
return x && typeof (x as Iterator<A>).next === 'function'
}
Returns true if a value is a List
.
See the code
export function isList<A = any>(x: any): x is List<A> {
if (Array.isArray(x)) return true
if (!x || typeof x !== 'object' || typeof x === 'string') return false
if (x.nodeType === 1) return !!x.length
if (x.length === 0) return true
if (x.length > 0) return x.hasOwnProperty(0) && x.hasOwnProperty(x.length - 1)
return false
}
Returns true if a value is a Map
.
See the code
export function isMap<A = any, B = any>(x: any): x is Map<A, B> {
return (
x && typeof (x as Map<A, B>).delete === 'function' && typeof (x as Map<A, B>).set === 'function'
)
}
Returns true if the value is null
See the code
export function isNull(x: any): x is null {
return x === null
}
Returns true if value is a number.
See the code
export function isNumber(x: any): x is number {
return typeof x === 'number'
}
Returns true if a value is an object.
See the code
export function isObject<A extends object = Object>(x: any): x is A {
return x && typeof x === 'object'
}
Returns true if a value is PromiseLike
See the code
export function isPromiseLike<A = any>(x: any): x is PromiseLike<A> {
return x && typeof x.then === 'function'
}
Returns true if a value is a Set.
See the code
export function isSet<A = any>(x: any): x is Set<A> {
return x && typeof (x as Set<A>).delete === 'function' && typeof (x as Set<A>).add === 'function'
}
Returns true if the value is undefined.
See the code
export function isUndefined(x: any): x is undefined {
return x === void 0
}
Compares two values using \<
See the code
export const lessThan: LessThan = curry2(<A>(right: A, left: A) => left < right)
export type LessThan = {
<A>(right: A, left: A): boolean
<A>(right: A): (left: A) => boolean
}
Compares 2 values using \<=
See the code
export const lessThanOrEqual: LessThanOrEqual = curry2(<A>(right: A, left: A) => left <= right)
export type LessThanOrEqual = {
<A>(right: A, left: A): boolean
<A>(right: A): (left: A) => boolean
}
Applies !
to a value.
See the code
export function not<A>(x: A): boolean {
return !x
}
Applies ||
between two predicate functions.
See the code
export const or: Or = curry3(__or)
export type Or = {
<A>(predicate1: Predicate<A>, predicate2: Predicate<A>, value: A): boolean
<A>(predicate1: Predicate<A>, predicate2: Predicate<A>): Predicate<A>
<A>(predicate1: Predicate<A>): {
(predicate2: Predicate<A>, value: A): boolean
(predicate2: Predicate<A>): Predicate<A>
}
}
function __or<A>(predicate1: Predicate<A>, predicate2: Predicate<A>, value: A): boolean {
return predicate1(value) || predicate2(value)
}
Returns true
if a given object's key value is equal to the given value
.
See the code
export const propEq: PropEq = curry3(function<O, K extends keyof O>(
key: K,
value: O[K],
obj: O
): boolean {
return equals(obj[key], value)
})
Returns the value at a given key if an object has that property, otherwise returns the defaultValue.
See the code
export const propOr: PropOr = curry3(__propOr)
function __propOr<A, K extends string>(defaultValue: A, key: K, obj: { [Key in K]: A }): A {
return obj.hasOwnProperty(key) ? obj[key] : defaultValue
}
export type PropOr = {
<A, K extends string>(defaultValue: A, key: K, obj: { [Key in K]: A }): A
<A, K extends string>(defaultValue: A, key: K): (obj: { [Key in K]: A }) => A
<A>(defaultValue: A): {
<K extends string>(key: K, obj: { [Key in K]: A }): A
<K extends string>(key: K): (obj: { [Key in K]: A }) => A
}
}
Given a list of arguments and a function, applies the function with the given arguments.
See the code
export const tryCatch = curry2(function apply<A, Err = any>(
list: List<any>,
f: (...args: Array<any>) => A
): Either<Err, A> {
switch (list.length) {
case 0:
return __catch(f)
case 1:
return __catch(() => f(list[0]))
case 2:
return __catch(() => f(list[0], list[1]))
case 3:
return __catch(() => f(list[0], list[1], list[2]))
case 4:
return __catch(() => f(list[0], list[1], list[2], list[3]))
case 5:
return __catch(() => f(list[0], list[1], list[2], list[3], list[4]))
default:
return __catch(() => f.apply(null, list))
}
}) as TryCatch
function __catch<A, Err = any>(f: () => A): Either<Err, A> {
try {
return Either.of(f())
} catch (error) {
return Either.left(error)
}
}
Returns the type of a value.
See the code
export function typeOf(value: string): 'String'
export function typeOf(value: number): 'Number'
export function typeOf(value: null): 'Null'
export function typeOf(value: undefined): 'Undefined'
export function typeOf(value: undefined): 'Undefined'
export function typeOf(value: any): string
export function typeOf(value: any): string {
if (value === null) return 'Null'
if (value === void 0) return `Undefined`
return Object.prototype.toString.call(value).slice(8, -1)
}