Simple functional programming library that works as you would expect.
Main purpose of the library is to reduce the amount of code that you need to write in your projects.
and make it much more readable
Library consists of core methods and namespaces that correspond to the following javascript types:
namespace | javascript type | documentation link |
---|---|---|
bool | boolean | bool |
num | number | num |
str | string | str |
obj | object | obj |
arr | array | arr |
Each namespace contains curried methods that work on the corresponding type.
Base fp methods | Conditionals | Other |
---|---|---|
Curry | Is | DoNothing |
Identity | Exists | TypeOf |
Const | IfElse | |
Variable | When | |
Swap | Unless | |
Call | InCase | |
ApplyOn | IndependentInCase | |
Pipe | CanBeDescribedAs | |
Compose | IsEither | |
Not | IsOfType |
Note that some methods in this section have aliases.
For example Const and Return are the same method.
Returns a curried version of a function.
Returned function returns itself if there were no arguments passed.
It may take not only one but multiple arguments at a time.
const add = (a, b) => a + b;
const curriedAdd = Curry(add);
const add2 = curriedAdd(2); // returns (x) => 2 + x
const four = curriedAdd(2, 2); // pass 2 args at a time
Function that returns first argument passed to it
const Identity = x => x
Const(Return) is a function that takes two arguments and returns the first one.
TRUE and FALSE are aliases for Const(true) and Const(false) respectively.
Useful to use as a higher order function to return the same value no matter the input.
const Const = (a, b) => a
Note that function examples in this tutorial just show function signatures. Actual functions in the library are curried.
Variable is a function that takes two arguments and returns the second one.
Function that optionally takes a single argument and does nothing.
(in js terms that means it returns undefined
).
Takes a predicate (a function that returns boolean) and returns a predicate
that returns true/false in opposite to the initial function cases.
Note that this function is one of a few that are not curried.
Function that takes two arguments and checks if they are equal using strict equality.
const IsNot = Not(Is)
Function that takes a single argument and checks if it's equal to null or undefined
using strict equality. Any other value is considered as existing.
const NotExists = Not(Exists);
Function that takes a binary function and returns a binary function that
does the same thing but takes second argument first.
const append = (appendingString, str) => str + appendingString;
const result1 = append('Hello ', 'world'); // "worldHello "
const prepend = Swap(append);
const result2 = prepend('Hello ', 'world'); // "Hello world"
Function that takes a function and an argument and returns
the result of calling that function with the argument
const Call = (f, x) => f(x)
const ApplyOn = Swap(Call)
Function that takes four arguments:
- unary predicate
- unary function
- unary function
- value
First, value is being passed to the predicate, if it returns
- true then the function will return the result of calling the first function with the value
- false then the function will return the result of calling the second function with the value
Function that takes three arguments:
- unary predicate
- unary function
- value
First, value is being passed to the predicate, if it returns
- true then the function will return the result of calling the function with the value
- false then the function will return the value itself
Function that takes three arguments:
- unary predicate
- unary function
- value
First, value is being passed to the predicate, if it returns
- true then the function will return the value itself
- false then the function will return the result of calling the function with the value
Function that takes two arguments:
- An array of binary tuples where every tuple contains:
- Unary predicate
- Unary function
- value
Value is passed to every unary predicate in order.
Function returns the result of passing value to the Unary function
of the first tuple where predicate returns true.
This function works similar to switch...case construction.
const value = 22;
const FORTY_FOUR = InCase([
[Is(2) , (v) => v - 2],
[Is(22), (v) => v * 2], // first tuple where predicate returns true for the value
// value is multiplied by 2 and returned
// using TRUE as the predicate for the last tuple is simmilar to using "default" in a switch case
[TRUE , Return(8)],
], value)
Function that takes two arguments:
- An array of binary tuples where every tuple contains:
- Unary predicate
- Unary function
- value
Works similar to InCase but returns
an array of results of passing value to unary functions where predicate returned true
Function takes two arguments:
- An array of unary predicates
- value
Checks if every predicate returns true when called with the value.
Function takes two arguments:
- An array of unary predicates
- value
Checks if at least one predicate returns true when called with the value.
Function takes two arguments:
- An array of unary functions
- value
Passes value to the first function and then the result to the next one,
invoking every function in order and returning the result of the last one
const Add = a => b => a + b;
const MultiplyBy = a => b => a * b;
const twelve = Pipe([
Add(2),
MultiplyBy(3),
], 2)
Function takes two arguments:
- An array of unary functions
- value
Works similar to Pipe
but calls functions in the reverse order.
Function takes two arguments:
- string representing a type, which can be
| "undefined" | "null" | "object" | "boolean"
| "number" | "bigint" | "string" | "symbol" | "function" | "array" |
- a value
Validates that value is of specified type. Works similar to typeof
but works correctly for null and array values.
Unary function that takes value and returns its type,
which can be one of the aforementioned strings.
Unary predicate that takes one argument returns true if argument is either true or false.
Binary predicate that takes two boolean arguments and returns true if both of them are true.
const And = (a, b) => a && b
Binary predicate that takes two boolean arguments and returns true if either of them is true.
Unary predicate that takes one argument returns true if argument is false.
Unary predicate that returns true if argument is of type number.
Binary predicate that returns true if second argument can be divided by the first without remainder.
const IsQuotientOf = (a, b) => b % a === 0
const True = IsQuotientOf(13, 39)
Unary predicate that returns true if argument is integer.
Unary predicate that returns true if argument is NaN.
Binary predicate that compares first argument to the second one.
- Gt - greater than
- Gte - greater than or equal
- Lt - less than
- Lte - less than or equal
const True = Gt(2, 3); // three is greater than 2
Unary predicate that returns true if argument is greater than 0 (IsPos) or less than 0 (IsNeg)
Function takes three numeric arguments:
- min
- max
- value
And returns true if value is greater than min and less than max.
Same as above but value can also be equal to the min or max.
Unary function that negates a numeric value
Increment (+1) and decrement (-1)
Binary function takes two arguments:
- max
- value
And returns max if value is greater than max and value if it's not
const AtMost = (max, x) => x > max ? max : x
Binary function takes two arguments:
- min
- value
And returns min if value is less than min and value if it's not
Binary functions that correspond to math operators (+, -, *, /, %)
Binary function that returns difference between two numeric values as absolute(positive) value
Unary function that rounds a value to the largest integer less than or equal to the value.
Unary function that rounds a value to the smallest integer greater than or equal to the value.
Unary function that removes decimal part of a number
Returns positive representation of a number
Function takes two arguments:
- extent
- value
And returns value raised to the extent
const ToExtent = (e, x) => x**e;
Unary function that turns a string into it's upper/lowercase version.
Unary function that removes whitespaces from a string on both sides or left side or right side respectively.
Unary function that takes an index(integer) and a string and returns a character at the index.
Unary function that takes an index(integer) and a string and returns a number in range 0 - 2^16 that represents UTF-16 code.
Function that takes three arguments:
- start
- end
- value
Extracts a section of the value and returns it as a new string.
Start and end are integers and can be negative.
Binary function that takes two arguments
- splitter
- value
The split() method divides a String into an ordered list of substrings,
puts these substrings into an array, and returns the array.
The division is done by searching for a pattern; where the pattern is provided
as the first parameter in the method's call and can be either Regex or a string.
Function takes two string arguments and returns the result of appending first argument to the second one.
const ConcatWith = (s1, s2) => s2 + s1; // note that s2 comes first
Function takes two arguments:
- regex
- value
Returns an array of substrings of the value string that matched the regex.
Binary predicate that takes a Regex and a string and returns true if string matches the regex.
Binary predicate that takes a number and a string and returns true if string length equals to the first argument.
Binary predicate that takes two strings and returns true if second string starts/ends with the first one.
Unary function that returns enumerable keys of an object.
Unary function that returns enumerable key-value pairs of an object as an array of binary tuples.
Unary function that takes an array of binary tuples where first values is a string and returns an object created using these entries.
For every tuple, first value (string) becomes an object key and second value becomes this key's value.
Unary function that returns a deep copy of an object, meaning that changing the result won't change the object that you passed to the function as argument.
Binary function that takes two arguments:
- defaultObject
- object
It returns a deep copy of the result of merging these two objects into one, with the
properties of the second having higher precedence.
Note If both objects have a nested object under the same key, the objects merge as well
Click to view example:
const defaultCat = {
name: 'Jonny',
age: 1,
cute: true,
parent: {
name: 'Jonny Jr',
age: 5,
}
};
const cat = {
name: 'Malcolm',
parent: {
name: 'Malcolm Jr',
cute: false
}
}
const result = WithDefault(defaultCat, cat);
const ResultWillBe = {
name: 'Malcolm', // overriden by cat
age: 1, // taken from default
cute: true, // taken from default
parent: {
cute: false, // taken from cat
name: 'Malcolm Jr',// overriden by cat
age: 5, // taken from default
}
}
const Impose = Swap(WithDefault)
First object's properties become more important.
Binary function that takes two arguments:
- array of strings
- object
Creates a new object with only the keys specified in the first argument.
Same as pick but excludes properties from object instead of picking them.
A binary function that takes two arguments:
- map specification
- source object
It maps one object(type) to another.
Map specification looks like this:
export type ObjectMapper<T1> = (value: any, obj: T1) => any;
export type ObjectMapSpec<T1, T2> = {
map:
[
keyof T1 | '',
ObjectMapper<T1> | ObjectMapSpec<any, any>,
keyof T2
][];
transfer?: Extract<keyof T1, keyof T2>[],
allowNull?: boolean
}
What these specification properties mean:
-
map
is an array of ternary tuples that look like this:- key of the source object or an empty string in case you want to create a new key in the resulting object
as opposed to mapping source key to a target one. - objectMapper is a binary function to map one key to another or another map specification to map one object to another
In case it's a function, it takes two arguments:- value of the source key or null if source key is an empty string
- source object
- key of the target object
- key of the source object or an empty string in case you want to create a new key in the resulting object
-
transfer
an array of keys that have the same name in the target object should be mapped usingIdentity
function, meaning their value should not change. -
allowNull
specifies whether this specification is able to handle null value as an object (by default it doesn't), for this to work, every object mapper function must handle case where both value and object are null and every nested map specification must also allow null value
Click to view example:
interface Cat {
name: string,
age: number,
cute: boolean,
weight: number,
kitten: Omit<Cat, 'kitten'>,
}
interface Dog {
name: string,
age: number,
brave: boolean,
weight: number,
puppy: Omit<Dog, 'puppy'>,
}
const KittenToPuppySpecification: ObjectMapSpec<Cat, Dog> = {
transfer: ['age', 'name'],
map: [
['', (_, kitten) => kitten.cute, 'brave'], // one way of making a dog brave in case cat was cute
['weight', (weight, kitten) => weight * 2, 'weight'],
],
allowNull: false
}
const CatToDogSpecification: ObjectMapSpec<Cat, Dog> = {
transfer: ['age', 'name'],
map: [
['cute', Identity, 'brave'], // another way of making a dog brave in case cat was cute
// note that specification can be passed here because kitten and puppy are objects
['kitten', KittenToPuppySpecification, 'puppy'],
['weight', (weight, kitten) => weight * 3, 'weight'],
],
allowNull: false
}
const cat: Cat = {
name: 'Marry',
age: 12,
cute: true,
weight: 3.5,
kitten: {
name: 'Jerry',
age: 4,
weight: 1.5,
cute: true,
}
}
const dog = Map(CatToDogSpecification, cat);
const DogResult = {
name: 'Marry', // transferred as it was
age: 12, // transferred as it was
brave: true, // because cat was cute
weight: 11.5, // cat weight (3.5) * 3
kitten: {
name: 'Jerry', // transferred from cat.kitten
age: 4, // transferred from cat.kitten
weight: 3, // kitten weight (1.5) * 2
brave: true, // because kitten was cute
}
}
A binary function that takes two arguments:
- validation specification
- an object
It checks whether object adheres to the specification.
and returns validation summary
Validation specification looks like this:
export type ValidationOptions<T extends DataObject> = {
// used to increase performance in case you are only interested in
// validity of an object and not in all the properties that are invalid
stopWhen?: (summary: ValidationSummary<T>) => boolean,
// allows you to create custom messages in case validator throws an exception
errorHandler?: (e: ValidationException) => string,
// should redundant properties make object invalid (true by default)
redundantIsError?: boolean,
// properties that are allowed to be null or undefined
optionalProps?: (keyof T)[],
// whether object itself is allowed to be null or undefined
isOptional?: boolean
}
export type ValidationPropertyRule<T1> = [
(v: any, o: T1) => boolean, // validator predicate function
string | ((v: any, k: keyof T1) => string) // message in case validator returns false
];
export type ValidationSpec<T1 extends DataObject> =
& Record<keyof T1, ValidationPropertyRule<T1>[] | AnyValidationSpec>
& { [ValidationOptionsSym]?: ValidationOptions<T1> };
Click to view example:
type CatChild = Partial<Omit<Cat, 'child'>>
type Cat = {
age: number;
name?: string;
amountOfLegs: number;
child: CatChild
}
type CatParent = {
age: number;
name?: string;
amountOfLegs: number;
childCat: Cat;
}
const CatChildSpec: obj.ValidationSpec<CatChild> = {
age: [
[IsOfType('number'), 'age must be a number']
],
name: [
[IsOfType('string'), 'name must be a number']
],
amountOfLegs: [
[IsOfType('number'), 'amountOfLegs must be a number']
],
[ValidationOptionsSym]: {
optionalProps: ['name', 'age', 'amountOfLegs']
}
}
const CatSpec: obj.ValidationSpec<Cat> = {
age: [
[IsOfType('number'), 'age must be a number']
],
name: [
[IsOfType('string'), 'name must be a number']
],
amountOfLegs: [
[IsOfType('number'), 'amountOfLegs must be a number']
],
child: CatChildSpec,
[ValidationOptionsSym]: {
optionalProps: ['name']
}
}
const CatParentSpec: obj.ValidationSpec<CatParent> = {
age: [
[IsOfType('number'), 'age must be a number']
],
name: [
[IsOfType('string'), 'name must be a number']
],
amountOfLegs: [
[IsOfType('number'), 'amountOfLegs must be a number']
],
childCat: CatSpec,
[ValidationOptionsSym]: {
optionalProps: ['name']
}
}
const cat: Cat = {
age: 1,
name: 1 as any, // SHOULD BE A STRING
amountOfLegs: 4,
child: {
name: 'Tonny jr',
age: '1' as any, // SHOULD BE A NUMBER
},
}
const catParent: CatParent = {
age: 1,
name: 'Tonny Sr',
amountOfLegs: '4' as any, // SHOULD BE A NUMBER
childCat: cat
}
const result = Validate(CatParentSpec, catParent);
const Result = {
"valid": false,
"errorCount": 3,
"missingProperties": [],
"redundantProperties": [],
"errors": {
"amountOfLegs": [
"amountOfLegs must be a number"
],
"childCat.name": [
"name must be a number"
],
"childCat.child.age": [
"age must be a number"
]
}
}
Result of the function is of type ValidationSummary:
export type ValidationSummary<T1 extends DataObject> = {
// whether object is valid
valid: boolean,
// how many errors occured in the process of validation
// in case of a valid object it's always 0
errorCount: number,
// valid object can not have missing properties
missingProperties: string[],
// valid object can not have redundant properties
// (unless stated otherwise in specification)
redundantProperties: string[],
// messages to understand what is wrong with the object
errors: Record<keyof T1 | '_self', string[]>
// _self is used to indicate that value that you passed to
// the validation function IS NOT AN OBJECT AT ALL
}
constructors | transformators | validators |
---|---|---|
OfValues | Select | IsArray |
OfLength | Exclude | AllElementsAre |
FromRange | Reduce | SomeElementsAre |
Map | NoElementIs | |
ConcatTo | ContainedIn | |
Nose, Tail | Contains | |
Head, Butt | IsSupersetOf | |
TakeNFirst, TakeNLast | IsSubsetOf | |
Append, Prepend | EqualsArray | |
Flatten | IsUnique | |
Intersection | ||
Subtract |
Function that takes multiple arguments of the same type and returns an array of them.
export const OfValues = <T>(...v: T[]) => [...v];
Unary function.
Creates an array of specified length filled with null
's.
const OfLength = (n: number) => Array(n).fill(null)
Takes three arguments:
- start
- finish (must be greater than start)
- step (must be integer)
And creates an array of numbers, starting from start up step by step until finish.
const result = arr.FromRange(1.5, 3.6, 1);
const Result = [1.5, 2.5, 3.5, 3.6]
Binary function that takes a predicate and an array. Alternative to Array.prototype.filter.
Binary function that takes a predicate and an array. Alternative to Array.prototype.filter but excludes values for which predicate returns true.
Ternary function that takes
- ternary function that takes
- accumulator
- array value
- array
- accumulator
- array
Alternative to Array.prototype.reduce.
Binary function that takes a mapper function and an array. Alternative to Array.prototype.map.
Binary function that takes two arrays and returns a new one that is result of pushing
all elements of the first array to the second one.
Unary function that returns a new array that contains all elements of the input array but
the last/first one. In case of an empty array input returns empty array
as well.
Unary function that returns first/last element of an array.
Doesn't change the array itself. In case of an empty array returns undefined
.
Binary function that takes a number and an array and returns a new array that contains first/last N values of the original array.
Binary function that takes two arguments: a value and an array and returns a
new array
that has value appended/prepended to it.
Turns an array that contains nested arrays into a flat array (array that doesn't contain array, only values).
const groupedArr = [
[1, 2],
[3, [4, 5]]
];
const numArr = arr.Flatten(groupedArr)
const Result = [1,2,3,4,5];
Binary function that takes two arrays and returns a new array that contains only elements that belong to both arrays simultaneously.
Binary function that takes two arrays and returns a new array that contains only elements that are contained in the second array and not in the first one.
Example:
// curried example
const remove1and2 = arr.Subtract([1,2]); // returns a function
const arr = [0,1,2,3,4];
const result = remove1and2(arr);
const Result = [0,3,4];
Unary predicate that takes a value and returns true if value is an array.
Binary predicate that takes an array and a unary predicate and returns true
if predicate returns true for every element in the array.
Alternative to Array.prototype.every
.
Binary predicate that takes an array and a unary predicate and returns true
if predicate returns true for at least one element in the array.
Alternative to Array.prototype.some
.
Binary predicate that takes an array and a unary predicate and returns true if predicate returns false for every element in the array.
Binary predicate that takes two arguments: an array and a value and returns true if array contains the value.
const Contains = Swap(ContainedIn);
Binary predicate that takes two arrays and returns true if all elements of the first array can be found in the second one.
const IsSubsetOf = Swap(IsSupersetOf);
Binary predicate that takes two arrays and returns true if arrays contain the same values. Order doesn't matter.
Unary predicate that takes an array and returns true if every element of the array is unique.