@apoyo/std
Version:
Typescript utility library
1,881 lines (1,874 loc) • 112 kB
TypeScript
declare const isNumber: (value: unknown) => value is number;
declare const isNaN: (value: number) => boolean;
declare const isNull: <A>(value: A | null) => value is null;
declare const isUndefined: <A>(value: A | undefined) => value is undefined;
declare const isObject: (input: unknown) => input is Record<string | number | symbol, unknown>;
declare const isFunction: (input: unknown) => input is Function;
declare function filter$2<A, B extends A>(fn: Dict.Refinement<A, B>): (dict: Dict<A>) => Dict<B>;
declare function filter$2<A>(fn: Dict.Predicate<A>): (arr: Dict<A>) => Dict<A>;
declare function reject$2<A, B extends A>(fn: Dict.Refinement<A, B>): (arr: Dict<A>) => Dict<InverseRefinement<A, B>>;
declare function reject$2<A>(fn: Dict.Predicate<A>): (arr: Dict<A>) => Dict<A>;
declare function omit(props: string[]): <A>(obj: Dict<A>) => Dict<A>;
declare function pick(props: string[]): <A>(obj: Dict<A>) => Dict<A>;
declare type Dict<A = any> = Record<string, A>;
declare namespace Dict {
interface Predicate<A> {
(value: A, key: string): boolean;
}
interface Refinement<A, B extends A> {
(value: A, key: string): value is B;
}
}
declare const Dict: {
/**
* @description
* Check if object is empty
*
* @example
* ```ts
* expect(Dict.isEmpty({})).toBe(true)
* ```
*/
isEmpty: (dict: Dict<unknown>) => boolean;
/**
* @description
* Get the value of a specific key from the dict
*
* @see `Dict.get`
*
* @example
* ```ts
* const value = pipe(
* {
* firstName: 'John',
* lastName: 'Doe'
* },
* Dict.lookup('lastName')
* )
*
* expect(value).toBe('Doe')
* ```
*/
lookup: (key: string | number) => <A>(dict: Dict<A>) => Option<A>;
/**
* @description
* Get the value of a specific key from the dict
*
* @see `Dict.lookup`
*
* @example
* ```ts
* const value = pipe(
* {
* firstName: 'John',
* lastName: 'Doe'
* },
* Dict.get('lastName')
* )
*
* expect(value).toBe('Doe')
* ```
*/
get: (key: string | number) => <A>(dict: Dict<A>) => Option<A>;
/**
* @description
* Set the value of a specific key in a `Dict`
*
* @sideEffects this method mutates the given `Dict`
*
* @example
* ```ts
* const original = {
* firstName: 'John'
* }
* const mutated = pipe(
* original,
* Dict.set('lastName', 'Doe')
* )
*
* expect(mutated === original).toBe(true)
* expect(mutated.lastName).toBe('Doe')
* ```
*/
set: <A_1>(key: string | number, value: A_1) => (dict: Dict<A_1>) => Dict<A_1>;
/**
* @description
* Calls a defined callback function on each element of a `Dict`.
* This function returns a new `Dict` that contains the results.
*
* @param fn - How to map each value
*
* @see `Dict.mapIndexed` if you need the key
*
* @example
* ```ts
* const result = pipe(
* {
* firstName: 'John',
* lastName: 'Doe'
* },
* Dict.map(Str.upper)
* )
*
* expect(attrs !== result).toBe(true)
* expect(result.firstName).toBe('JOHN')
* expect(result.lastName).toBe('DOE')
* ```
*/
map: <A_2, B>(fn: (value: A_2) => B) => (dict: Dict<A_2>) => Dict<B>;
/**
* @description
* Calls a defined callback function on each element of a `Dict`.
* This function returns a new `Dict` that contains the results.
*
* @param fn - How to map each value
*
* @see `Dict.map` if you don't need the key
*
* @example
* ```ts
* const result = pipe(
* {
* firstName: 'John',
* lastName: 'Doe'
* },
* Dict.map((str, key) => `${key} = ${str}`)
* )
*
* expect(attrs !== result).toBe(true)
* expect(result.firstName).toBe('firstName = John')
* expect(result.lastName).toBe('lastName = Doe')
* ```
*/
mapIndexed: <A_3, B_1>(fn: (value: A_3, key: string) => B_1) => (dict: Dict<A_3>) => Dict<B_1>;
/**
* @description
* Filter items out of the array
*
* @param fn - Predicate or refinement on which items to keep in the `Dict`
*
* @see `Dict.reject`
* @see `Dict.filterMap`
*
* @example
* ```ts
* const result = pipe(
* {
* nb1: 1,
* nb2: -3,
* nb3: 2,
* },
* Dict.filter(value => value >= 0)
* )
*
* expect(result).toEqual({
* nb1: 1,
* nb3: 2
* })
* ```
*/
filter: typeof filter$2;
/**
* @description
* Filter items out of the array
*
* @param fn - Predicate or refinement on which items to remove from the `Dict`
*
* @see `Dict.filter`
* @see `Dict.filterMap`
*
* @example
* ```ts
* const result = pipe(
* {
* nb1: 1,
* nb2: -3,
* nb3: 2,
* },
* Dict.reject(value => value >= 0)
* )
*
* expect(result).toEqual({
* nb2: -3
* })
* ```
*/
reject: typeof reject$2;
/**
* @description
* Map and filter `undefined` values out of the `Dict`
*
* @param fn - How to map each value of the `Dict`
*
* @see `Dict.filter`
* @see `Dict.reject`
* @see `Dict.compact`
*
* @example
* ```ts
* const result = pipe(
* {
* firstName: "John",
* lastName: null
* },
* Dict.filterMap(value => value !== null
* ? pipe(value, Str.upper)
* : undefined
* )
* )
*
* expect(result).toEqual({
* firstName: "JOHN"
* })
* ```
*/
filterMap: <A_4, B_2>(fn: (value: A_4, key: string) => Option<B_2>) => (dict: Dict<A_4>) => Dict<B_2>;
/**
* @description
* Filter `undefined` values out of the `Dict`
*
* @see `Dict.filterMap`
*
* @example
* ```ts
* const values = pipe(
* {
* firstName: "John",
* lastName: undefined
* },
* Dict.compact
* )
*
* expect(values).toEqual({
* firstName: "John"
* })
* ```
*/
compact: <A_5>(value: Dict<Option<A_5>>) => Dict<A_5>;
/**
* @description
* Iterate through and accumulate / aggregate a value with a `Dict`
*
* @example
* ```ts
* const value = pipe(
* {
* nb1: 2,
* nb2: 5,
* nb3: 3
* },
* Dict.reduce((a, b) => a + b, 0)
* )
*
* expect(value).toEqual(10)
* ```
*/
reduce: <A_6, B_3>(fn: (acc: B_3, value: A_6, key: string) => B_3, initial: B_3) => (dict: Dict<A_6>) => B_3;
/**
* @description
* Map over a `Dict` and return an array
*
* @see `Dict.keys`
* @see `Dict.values`
* @see `Dict.toPairs`
*
* @example
* ```ts
* const arr = pipe(
* {
* nb1: 1,
* nb2: -3,
* nb3: 2
* },
* Dict.collect((value, key) => [key, value])
* )
*
* expect(arr).toEqual([
* ['nb1', 1],
* ['nb2', -3],
* ['nb3', 2]
* ])
* ```
*/
collect: <A_7, B_4>(fn: (value: A_7, key: string) => B_4) => (dict: Dict<A_7>) => B_4[];
/**
* @description
* Checks if the variable is an object
*/
isDict: (input: unknown) => input is Dict<unknown>;
/**
* @description
* Collect all keys of the `Dict`
*
* @see `Dict.collect`
* @see `Dict.values`
* @see `Dict.toPairs`
*
* @example
* ```ts
* const arr = Dict.keys({ firstName: 'John' })
* expect(arr).toEqual(['firstName'])
* ```
*/
keys: <A_8>(dict: Dict<A_8>) => Array<string>;
/**
* @description
* Collect all values of the `Dict`
*
* @see `Dict.collect`
* @see `Dict.keys`
* @see `Dict.toPairs`
*
* @example
* ```ts
* const arr = Dict.values({ firstName: 'John' })
* expect(arr).toEqual(['John'])
* ```
*/
values: <A_9>(dict: Dict<A_9>) => A_9[];
/**
* @description
* Create a dict from an array of key/value pairs
*
* @see `Dict.toPairs`
*
* @example
* ```ts
* const dict = Dict.fromPairs([
* ['firstName', 'John'],
* ['lastName', 'Doe']
* ])
* expect(dict).toEqual({
* firstName: 'John',
* lastName: 'Doe'
* })
* ```
*/
fromPairs: <A_10>(pairs: [string | number, A_10][] | (readonly [string | number, A_10])[]) => Dict<A_10>;
/**
* @description
* Create an array of key/value pairs from the `Dict`
*
* @see `Dict.collect`
* @see `Dict.keys`
* @see `Dict.values`
* @see `Dict.fromPairs`
*
* @example
* ```ts
* const arr = Dict.toPairs({
* firstName: 'John',
* lastName: 'Doe'
* })
* expect(arr).toEqual([
* ['firstName', 'John'],
* ['lastName', 'Doe']
* ])
* ```
*/
toPairs: <A_11>(dict: Dict<A_11>) => [string, A_11][];
/**
* @description
* Merge both `Dict`s.
* The values of the member `Dict` have higher priority than the original `Dict`.
*
* As such, this method corresponds to:
* ```ts
* {
* ...original,
* ...member
* }
* ```
*
* @param member - The `Dict` with which the original `Dict` should be combined
*
* @example
* ```ts
* const merged = pipe(
* {
* firstName: 'John',
* lastName: 'Doe'
* },
* Dict.concat({
* lastName: 'Smith',
* gender: 'M'
* })
* )
*
* expect(merged).toEqual({
* firstName: 'John',
* lastName: 'Smith',
* gender: 'M'
* })
* ```
*/
concat: <A_12>(member: Dict<A_12>) => (dict: Dict<A_12>) => Dict<A_12>;
/**
* @description
* Merge both `Dict`s.
* The values of the original `Dict` have higher priority than the member `Dict`.
*
* As such, this method corresponds to:
* ```ts
* {
* ...member,
* ...original
* }
* ```
*
* @param member - The `Dict` with which the original `Dict` should be combined
*
* @example
* ```ts
* const merged = pipe(
* {
* firstName: 'John',
* lastName: 'Doe'
* },
* Dict.union({
* lastName: 'Smith',
* gender: 'M'
* })
* )
*
* expect(merged).toEqual({
* firstName: 'John',
* lastName: 'Doe',
* gender: 'M'
* })
* ```
*/
union: <A_13>(member: Dict<A_13>) => (dict: Dict<A_13>) => Dict<A_13>;
/**
* @description
* Intersection of both `Dict`s based on their keys.
* This means, only the keys that are both in `member` and the original `Dict` will be kept.
*
* @param member - The `Dict` with which the original `Dict` should be intersected
*
* @example
* ```ts
* const intersection = pipe(
* {
* firstName: 'John',
* lastName: 'Doe'
* },
* Dict.intersect({
* lastName: 'Smith',
* gender: 'M'
* })
* )
*
* expect(intersection).toEqual({
* lastName: 'Doe'
* })
* ```
*/
intersect: <A_14>(member: Dict<A_14>) => (dict: Dict<A_14>) => Dict<A_14>;
/**
* @description
* The difference between both `Dict`s based on their keys.
* This means, all keys in `member` will be removed from the original `Dict`.
*
* @param member - The `Dict` with all keys to remove from the original `Dict`
*
* @example
* ```ts
* const diff = pipe(
* {
* firstName: 'John',
* lastName: 'Doe'
* },
* Dict.difference({
* lastName: 'Smith',
* gender: 'M'
* })
* )
*
* expect(diff).toEqual({
* firstName: 'John'
* })
* ```
*/
difference: <A_15>(member: Dict<A_15>) => (dict: Dict<A_15>) => Dict<A_15>;
/**
* @description
* Returns a new dict without the specified keys
*/
omit: typeof omit;
/**
* @description
* Returns a new dict containing only the specified keys
*/
pick: typeof pick;
};
declare type Falsy = null | undefined | '' | 0 | false;
declare type None = undefined;
declare type Some<A> = A extends undefined ? never : A;
declare function filter$1<A, B extends A>(fn: Refinement<A, B>): (value: Option<A>) => Option<B>;
declare function filter$1<A>(fn: Predicate<A>): (value: Option<A>) => Option<A>;
declare function reject$1<A, B extends A>(fn: Refinement<A, B>): (value: Option<A>) => Option<B>;
declare function reject$1<A>(fn: Predicate<A>): (value: Option<A>) => Option<A>;
declare function get(onNone: () => never): <A>(value: Option<A>) => never;
declare function get(onNone: () => never[]): <A extends any[]>(value: Option<A>) => Some<A>;
declare function get(defaultValue: never[]): <A extends any[]>(value: Option<A>) => Some<A>;
declare function get<B>(onNone: () => B): <A>(value: Option<A>) => Some<A> | B;
declare function get<B>(defaultValue: B): <A>(value: Option<A>) => Some<A> | B;
declare function throwError$1<A>(onNone: () => Error): (value: Option<A>) => A;
declare function throwError$1<A>(err: Error): (value: Option<A>) => A;
declare type Option<A> = A | undefined;
declare namespace Option {
type OptionProps<A extends Dict<unknown>> = {
[P in keyof A]: A[P] extends Some<A[P]> ? never : P;
}[keyof A];
type SomeProps<A extends Dict<unknown>> = {
[P in keyof A]: A[P] extends Some<A[P]> ? P : never;
}[keyof A];
export type Struct<A> = A extends Dict<unknown> ? {
[P in SomeProps<A>]: A[P] extends Dict<unknown> ? Struct<A[P]> : A[P];
} & {
[P in OptionProps<A>]?: A[P] extends Dict<unknown> ? Struct<A[P]> : A[P];
} : A;
export {};
}
/**
* @namespace Option
*
* @description
*
* The `Option` namespace contains utilities to improve the handling of optional values.
* The `Option` type is expressed as following:
*
* ```ts
* type Option<A> = A | undefined
* ```
*
* **Note**: In other libraries, the `Option` type is often either `Some` value, or `None` / `Nothing`.
*
*/
declare const Option: {
/**
* @description
* Check if an optional value is not `undefined`
*/
isSome: <A>(value: Option<A>) => value is A;
/**
* @description
* Check if an optional value is `undefined`
*/
isNone: <A_1>(value: Option<A_1>) => value is undefined;
/**
* @description
* Map over an optional value, without worrying about the value being undefined
*
* @example
* ```ts
* const a: Option<number> = undefined
* const b = pipe(
* a,
* Option.map(nb => nb * 2)
* )
*
* expect(b).toBe(undefined)
* ```
*/
map: <A_2, B>(fn: (value: A_2) => Option<B>) => (value: Option<A_2>) => Option<B>;
/**
* @description
* If the predicate is false, the value becomes `undefined`
*
* @see `Option.reject`
*
* @example
* ```ts
* const result = pipe(
* NaN,
* Option.filter(nb => !isNaN(nb))
* )
*
* expect(result).toBe(undefined)
* ```
*/
filter: typeof filter$1;
/**
* @description
* If the predicate is true, the value becomes `undefined`
*
* @see `Option.filter`
*
* @example
* ```ts
* const result = pipe(
* NaN,
* Option.reject(nb => isNaN(nb))
* )
*
* expect(result).toBe(undefined)
*/
reject: typeof reject$1;
/**
* @description
* For a given `Option<A>`, returns either:
* - The value `A`
* - The given default value if the optional value is `undefined`
*
* @see `Option.throwError`
*
* @example
* ```ts
* const a: Option<number> = undefined
* const b: number = pipe(
* nb,
* Option.get(0)
* )
*
* expect(b).toBe(0)
* ```
*/
get: typeof get;
/**
* @description
* For a given `Option<A>`, either:
* - Return the value `A`
* - Throw the given error if the optional value is `undefined`
*
* @see `Option.get`
*
* @example
* ```ts
* const a: Option<number> = undefined
* const b: number = pipe(
* nb,
* Option.get(0)
* )
*
* expect(b).toBe(0)
* ```
*/
throwError: typeof throwError$1;
/**
* @description
* Returns an optional value from a nullable value
*
* @example
* ```ts
* const a: number | null = null
* const b: Option<number> = Option.fromNullable(a)
*
* expect(b).toBe(undefined)
* ```
*/
fromNullable: <T>(value: T | null) => Option<T>;
/**
* @description
* Returns an optional value from a falsy value
*
* **Note**: In Javascript, a falsy value may be undefined, null, 0, false and ""
*
* @example
* ```ts
* const a: number = 0
* const b: Option<number> = Option.fromFalsy(a)
*
* expect(b).toBe(undefined)
* ```
*/
fromFalsy: <T_1>(value: Falsy | T_1) => Option<T_1>;
/**
* @description
* Returns an optional value from an empty string
*
* @example
* ```ts
* const a: string = ""
* const b: Option<string> = Option.fromString(a)
*
* expect(b).toBe(undefined)
* ```
*/
fromString: <T_2>(value: string | T_2) => Option<string | T_2>;
/**
* @description
* Returns an optional value from a number
*
* @example
* ```ts
* const a: number = NaN
* const b: Option<number> = Option.fromNumber(a)
*
* expect(b).toBe(undefined)
* ```
*/
fromNumber: (value: number) => Option<number>;
/**
* @description
* Returns an optional value from a Date object
*
* @example
* ```ts
* const a: Date = new Date("invalid")
* const b: Option<Date> = Option.fromDate(a)
*
* expect(b).toBe(undefined)
* ```
*/
fromDate: (value: Date) => Option<Date>;
};
/**
* @description
* A constant enum for possible `Ord` results
*
* @example
* ```ts
* expect(Ord.number(1, 0)).toBe(Ordering.UP)
* expect(Ord.number(0, 1)).toBe(Ordering.DOWN)
* expect(Ord.number(0, 0)).toBe(Ordering.EQ)
* ```
*/
declare const enum Ordering {
UP = 1,
DOWN = -1,
EQ = 0
}
declare function concat<A>(...ords: [Ord<A>]): Ord<A>;
declare function concat<A, B>(...ords: [Ord<A>, Ord<B>]): Ord<A & B>;
declare function concat<A, B, C>(...ords: [Ord<A>, Ord<B>, Ord<C>]): Ord<A & B & C>;
declare function concat<A, B, C, D>(...ords: [Ord<A>, Ord<B>, Ord<C>, Ord<D>]): Ord<A & B & C & D>;
declare function concat<A, B, C, D, E>(...ords: [Ord<A>, Ord<B>, Ord<C>, Ord<D>, Ord<E>]): Ord<A & B & C & D & E>;
declare function concat<A, B, C, D, E, F>(...ords: [Ord<A>, Ord<B>, Ord<C>, Ord<D>, Ord<E>, Ord<F>]): Ord<A & B & C & D & E & F>;
declare function eq<A>(ord: Ord<A>): {
<X extends A, Y extends A>(x: X, y: Y): boolean;
<Y_1 extends A>(y: Y_1): <X_1 extends A>(x: X_1) => boolean;
};
declare function lt<A>(ord: Ord<A>): {
<X extends A, Y extends A>(x: X, y: Y): boolean;
<Y_1 extends A>(y: Y_1): <X_1 extends A>(x: X_1) => boolean;
};
declare function lte<A>(ord: Ord<A>): {
<X extends A, Y extends A>(x: X, y: Y): boolean;
<Y_1 extends A>(y: Y_1): <X_1 extends A>(x: X_1) => boolean;
};
declare function gt<A>(ord: Ord<A>): {
<X extends A, Y extends A>(x: X, y: Y): boolean;
<Y_1 extends A>(y: Y_1): <X_1 extends A>(x: X_1) => boolean;
};
declare function gte<A>(ord: Ord<A>): {
<X extends A, Y extends A>(x: X, y: Y): boolean;
<Y_1 extends A>(y: Y_1): <X_1 extends A>(x: X_1) => boolean;
};
declare function min<A>(ord: Ord<A>): {
<X extends A, Y extends A>(x: X, y: Y): X | Y;
<Y_1 extends A>(y: Y_1): <X_1 extends A>(x: X_1) => Y_1 | X_1;
};
declare function max<A>(ord: Ord<A>): {
<X extends A, Y extends A>(x: X, y: Y): X | Y;
<Y_1 extends A>(y: Y_1): <X_1 extends A>(x: X_1) => Y_1 | X_1;
};
declare type Ord<A> = {
name: string;
(a: A, b: A): Ordering;
};
/**
* @namespace Ord
*
* @description
* This namespace contains utilities to create simple or more complex ordering / sorting functions.
*
* These `Ord` functions can be used for a multitude of use-cases:
*
* @see `Arr.sort` - To sort an array
* @see `Arr.min` - To return the smallest value in an array
* @see `Arr.max` - To return the biggest value in an array
*
*/
declare const Ord: {
/**
* @description
* Order strings
*/
string: Ord<string>;
/**
* @description
* Order numbers
*/
number: Ord<number>;
/**
* @description
* Order booleans.
*
* The value `false` comes first.
*/
boolean: Ord<boolean>;
/**
* @description
* Order date object.
*
* This function does not check if the date is valid
*/
date: Ord<Date>;
/**
* @description
* Create an order function for a custom type or object
*
* @example
* ```ts
* const ordTodo = pipe(
* Ord.string,
* Ord.contramap((todo: Todo) => todo.title)
* )
* ```
*/
contramap: <A, B>(fn: (value: A) => B) => (ord: Ord<B>) => Ord<A>;
/**
* @description
* Inverse the order function
*
* @example
* ```ts
* const numberDesc = pipe(
* Ord.number,
* Ord.inverse
* )
*
* const nbs = pipe(
* [1,3,2,4],
* Arr.sort(numberDesc)
* )
*
* expect(nbs).toEqual([4,3,2,1])
* ```
*/
inverse: <A_1>(ord: Ord<A_1>) => Ord<A_1>;
/**
* @description
* Allow the ordering function to take optional (undefined) values.
*
* Undefined values are placed last.
*
* @see `Ord.nullable` for nullable values
*
* @example
* ```ts
* const optionalNb = pipe(
* Ord.number,
* Ord.optional
* )
*
* const nbs = pipe(
* [1,3,undefined,2],
* Arr.sort(optionalNb)
* )
*
* expect(nbs).toEqual([1,2,3,undefined])
* ```
*/
optional: <A_2>(ord: Ord<A_2>) => Ord<Option<A_2>>;
/**
* @description
* Allow the ordering function to take nullable values.
*
* Nullable values are placed last.
*
* @see `Ord.optional` for optional (undefined) values
*
* @example
* ```ts
* const optionalNb = pipe(
* Ord.number,
* Ord.nullable
* )
*
* const nbs = pipe(
* [1,3,null,2],
* Arr.sort(optionalNb)
* )
*
* expect(nbs).toEqual([1,2,3,null])
* ```
*/
nullable: <A_3>(ord: Ord<A_3>) => Ord<A_3 | null>;
/**
* @description
* Combine multiple `Ord`s.
*
* The first `Ord` is executed first.
* If the elements are equal, the second `Ord` is executed, and so forth...
*
* @example
* ```ts
* const ordDone = pipe(
* Ord.boolean,
* Ord.contramap((todo: Todo) => todo.done)
* )
* const ordName = pipe(
* Ord.string,
* Ord.contramap((todo: Todo) => todo.name)
* )
*
* // Order first by "done", then by "name"
* const ordTodo = Ord.concat(ordDone, ordName)
*
* const todos = pipe(
* todos,
* Arr.sort(ordTodo)
* )
* ```
*/
concat: typeof concat;
/**
* @description
* Create "equals" comparator from `Ord`
*
* @example
* ```ts
* const eqName = pipe(
* Ord.string,
* Ord.contramap((todo: Todo) => todo.name),
* Ord.eq
* )
*
* // Find todo with the name "Buy bread"
* const todo = todos.find(eqName("Buy bread"))
* ```
*/
eq: typeof eq;
/**
* @description
* Create "lower than" comparator from `Ord`
*
* @see `Ord.lte` for "lower than equals"
* @see `Ord.gt` for "greater than"
* @see `Ord.gte` for "greater than equals"
*
* @example
* ```ts
* const ltNumber = pipe(
* Ord.number,
* Ord.lt
* )
*
* // Only retain numbers under 4
* const nbs = [1,3,6,2,4].filter(ltNumber(4))
*
* expect(nbs).toEqual([1,3,2])
* ```
*/
lt: typeof lt;
/**
* @description
* Create "lower than equals" comparator from `Ord`
*
* @see `Ord.lt` for "lower than"
* @see `Ord.gt` for "greater than"
* @see `Ord.gte` for "greater than equals"
*
* @example
* ```ts
* const lteNumber = pipe(
* Ord.number,
* Ord.lte
* )
*
* // Only retain numbers under or equals to 4
* const nbs = [1,3,6,2,4].filter(lteNumber(4))
*
* expect(nbs).toEqual([1,3,2,4])
* ```
*/
lte: typeof lte;
/**
* @description
* Create "greater than" comparator from `Ord`
*
* @see `Ord.lt` for "lower than"
* @see `Ord.lte` for "lower than equals"
* @see `Ord.gte` for "greater than equals"
*
* @example
* ```ts
* const gtNumber = pipe(
* Ord.number,
* Ord.gt
* )
*
* // Only retain numbers greater than 4
* const nbs = [1,3,6,2,4].filter(gtNumber(4))
*
* expect(nbs).toEqual([6])
* ```
*/
gt: typeof gt;
/**
* @description
* Create "greater than equals" comparator from `Ord`
*
* @see `Ord.lt` for "lower than"
* @see `Ord.lte` for "lower than equals"
* @see `Ord.gt` for "greater than"
*
* @example
* ```ts
* const gteNumber = pipe(
* Ord.number,
* Ord.gte
* )
*
* // Only retain numbers greater or equals to 4
* const nbs = [1,3,6,2,4].filter(gteNumber(4))
*
* expect(nbs).toEqual([6,4])
* ```
*/
gte: typeof gte;
/**
* @description
* Create a function which returns the smallest element from an `Ord`
*
* @see `Ord.max`
*
* @example
* ```ts
* const minDate = pipe(
* Ord.date,
* Ord.min
* )
*
* const date = minDate(new Date('2020'), new Date('2021'))
*
* expect(date).toBe(new Date('2020'))
* ```
*/
min: typeof min;
/**
* @description
* Create a function which returns the greatest element from an `Ord`
*
* @see `Ord.min`
*
* @example
* ```ts
* const maxDate = pipe(
* Ord.date,
* Ord.max
* )
*
* const date = maxDate(new Date('2020'), new Date('2021'))
*
* expect(date).toBe(new Date('2021'))
* ```
*/
max: typeof max;
};
declare function fromArray<A>(arr: Readonly<NonEmptyArray<A>>): NonEmptyArray<A>;
declare function fromArray<A>(arr: NonEmptyArray<A>): NonEmptyArray<A>;
declare function fromArray<A>(arr: A[]): Option<NonEmptyArray<A>>;
declare type NonEmptyArray<A> = [A, ...A[]];
/**
* @namespace NonEmptyArray
*
* @description
*
* A `NonEmptyArray` is an array containing at least 1 item.
* This means, that some function will always return a value, compared to the `Arr` utility variant.
*
* **Note**: An `NonEmptyArray` variable can still use all of the utilities of the `Arr` namespace.
*
* ```ts
* const arrayA: Array<number> = []
* const arrayB: NonEmptyArray<number> = [1]
*
* const a: Option<number> = Arr.head(arrayA)
* const b: number = NonEmptyArray.head(arrayB)
* ```
*/
declare const NonEmptyArray: {
/**
* @description
* Create a new NonEmptyArray, containing at least one element
*/
of: <A>(value: A) => NonEmptyArray<A>;
/**
* @description
* Transforms an array into a `NonEmptyArray`
* If the array is empty, the function will return `undefined` instead
*/
fromArray: typeof fromArray;
/**
* @description
* Returns the first value in the `NonEmptyArray`
*
* @see `Arr.head`
* @see `NonEmptyArray.last`
*
* @example
* ```ts
* const first = pipe(
* [1,2,3,4],
* Arr.head
* )
*
* expect(first).toEqual(1)
* ```
*/
head: <A_1>(arr: NonEmptyArray<A_1> | readonly [A_1, ...A_1[]]) => A_1;
/**
* @description
* Returns the last value in the `NonEmptyArray`
*
* @see `Arr.last`
* @see `NonEmptyArray.head`
*
* @example
* ```ts
* const last = pipe(
* [1,2,3,4],
* Arr.last
* )
*
* expect(last).toEqual(4)
* ```
*/
last: <A_2>(arr: NonEmptyArray<A_2> | readonly [A_2, ...A_2[]]) => A_2;
/**
* @description
* Calls a defined callback function on each element of an `NonEmptyArray`, and returns a new `NonEmptyArray` that contains the results.
*
* @param fn - How to map each value
*
* @see `NonEmptyArray.mapIndexed` if you need the index
*
* @example
* ```ts
* const nbs = pipe(
* [1,2,3],
* NonEmptyArray.map(a => a + 1)
* )
*
* expect(nbs).toEqual([2,3,4])
* ```
*/
map: <A_3, B>(fn: (value: A_3) => B) => (arr: NonEmptyArray<A_3> | readonly [A_3, ...A_3[]]) => NonEmptyArray<B>;
/**
* @description
* Calls a defined callback function on each element of an `NonEmptyArray`, and returns a new `NonEmptyArray` that contains the results.
*
* @param fn - How to map each value
*
* @see `NonEmptyArray.map` if you don't need the index
*
* @example
* ```ts
* const nbs = pipe(
* [1,2],
* NonEmptyArray.mapIndexed((a, index) => `index ${index} = ${a}`)
* )
*
* expect(nbs).toEqual([
* `index 0 = 1`,
* `index 1 = 2`
* ])
* ```
*/
mapIndexed: <A_4, B_1>(fn: (value: A_4, index: number) => B_1) => (arr: NonEmptyArray<A_4> | readonly [A_4, ...A_4[]]) => NonEmptyArray<B_1>;
/**
* @description
* Returns the smallest value in the array.
*
* @param ord - The order is used to determine which element is smaller
*
* @see `Arr.min`
* @see `NonEmptyArray.min`
*
* @example
* ```ts
* const smallestNb = pipe(
* [1, 7, 3, 4, 2],
* NonEmptyArray.min(Ord.number)
* )
*
* expect(smallestNb).toBe(1)
* ```
*/
min: <A_5>(ord: Ord<A_5>) => <C extends A_5>(arr: NonEmptyArray<C> | readonly [C, ...C[]]) => C;
/**
* @description
* Returns the greatest value in the array.
*
* @param ord - The order is used to determine which element is greater
*
* @see `Arr.max`
* @see `NonEmptyArray.min`
*
* @example
* ```ts
* const greatestNb = pipe(
* [1, 7, 3, 4, 2],
* NonEmptyArray.max(Ord.number)
* )
*
* expect(greatestNb).toBe(7)
* ```
*/
max: <A_6>(ord: Ord<A_6>) => <C_1 extends A_6>(arr: NonEmptyArray<C_1> | readonly [C_1, ...C_1[]]) => C_1;
/**
* @description
* Sort array by the given `Ord` function.
*
* This function is the same as `Arr.sort`, but for `NonEmptyArray`s.
*
* @param ord - The order is used to determine which element is greater
*
* @example
* ```ts
* const nbs = pipe(
* [1,4,2,3],
* NonEmptyArray.sort(Ord.number)
* )
*
* expect(nbs).toEqual([1,2,3,4])
* ```
*/
sort: <A_7>(ord: Ord<A_7>) => <C_2 extends A_7>(arr: NonEmptyArray<C_2> | readonly [C_2, ...C_2[]]) => NonEmptyArray<C_2>;
};
declare const enum Tags {
Ok = "Result.Ok",
Ko = "Result.Ko"
}
interface Ok<T> {
_tag: Tags.Ok;
ok: T;
}
interface Ko<T> {
_tag: Tags.Ko;
ko: T;
}
declare type Struct<T extends Dict> = {
[P in keyof T]: T[P] extends Ok<infer A> ? A : never;
};
declare type StructErrors<T extends Dict> = {
[P in keyof T]: T[P] extends Ko<infer E> ? E : never;
}[keyof T];
declare type Result<A, E = unknown> = Ok<A> | Ko<E>;
/**
* @namespace Result
*
* @description
* A `Result` can either `Ok` or `Ko`:
* - `Ok` signifies the operation succeeded
* - `Ko` signifies the operation failed
*
* A `Result`, being a simple variable, may also allow you to handle multiple operations that may fail, without throwing / stopping on the first failure
*
* @example
* ```ts
* const divide = (a, b) => {
* if (b === 0) {
* throw Err.of('cannot divide {a} by {b}', { a, b })
* }
* return a / b
* }
*
* const [ok, ko] = pipe(
* [ [3,1], [3,0], [1,2], [4,0] ],
* Arr.map(([a, b]) => Result.tryCatch(() => divide(a, b))),
* Arr.separate
* )
* ```
*/
declare const Result: {
/**
* @description
* Create an `Ok` value
*/
ok: <T>(value: T) => Ok<T>;
/**
* @description
* Create a `Ko` value
*/
ko: <T_1>(value: T_1) => Ko<T_1>;
/**
* @description
* Check if the result is `Ok`
*
* @example
* ```ts
* const result = Result.ok(1)
*
* if (Result.isOk(result)) {
* console.log(result.ok)
* }
* ```
*/
isOk: <A, B>(result: Result<A, B>) => result is Ok<A>;
/**
* @description
* Check if the result is `Ko`
*
* @example
* ```ts
* const result = Result.ko(new Error('some error occured'))
*
* if (Result.isKo(result)) {
* console.log(result.ko)
* }
* ```
*/
isKo: <A_1, B_1>(result: Result<A_1, B_1>) => result is Ko<B_1>;
/**
* @description
* Check if unknown variable is a `Result`
*/
isResult: <A_2 = unknown, B_2 = unknown>(result: unknown) => result is Result<A_2, B_2>;
/**
* @description
* Create a `Result` from an optional value
*
* @example
* ```ts
* const user: Result<User, Error> = pipe(
* users,
* Arr.find(u => u.id === 'xxxx'),
* Result.fromOption(() => new Error('could not find user'))
* )
* ```
*/
fromOption: <E = unknown>(onNone: () => E) => <A_3>(option: Option<A_3>) => Result<A_3, E>;
/**
* @description
* Returns value if the result is `Ok`, or throws value if result is `Ko`.
*
* @description
* ```ts
* const result = Result.ko(new Error('some error'))
*
* try {
* const value = Result.get(result)
* } catch (err) {
* expect(err.message).toBe('some error')
* }
* ```
*/
get: <A_4, E_1 = unknown>(result: Result<A_4, E_1>) => A_4;
/**
* @description
* Transforms the result into a tuple [ value, error ]
*
* @example
* ```ts
* const [value, error] = Result.tryCatch(() => {
* throw new Error('Unknown')
* })
*
* expect(value).toBe(undefined)
* expect(error?.message).toBe('Unknown')
* ```
*/
tuple: <A_5, E_2 = unknown>(result: Result<A_5, E_2>) => [Option<A_5>, Option<E_2>];
/**
* @description
* Map over the `Ok` value of the `Result`.
* The callback is not called if the result is `Ko`.
*
* @see `Result.mapError` - If you want to map over the `Ko` value instead
*
* @example
* ```ts
* const result = pipe(
* Result.ok(1),
* Result.map(nb => nb + 1)
* )
*
* expect(result).toEqual(Result.ok(2))
* ```
*/
map: <A_6, B_3>(fn: (value: A_6) => B_3) => <E_3 = unknown>(result: Result<A_6, E_3>) => Result<B_3, E_3>;
/**
* @description
* Map over the `Ko` value of the `Result`.
* The callback is not called if the result is `Ok`.
*
* @see `Result.map` - If you want to map over the `Ok` value instead
*
* @example
* ```ts
* const result = pipe(
* Result.ko(new Error('some error')),
* Result.mapError(Err.chain('operation failed'))
* )
* ```
*/
mapError: <B_4, E_4 = unknown>(fn: (value: E_4) => B_4) => <A_7>(result: Result<A_7, E_4>) => Result<A_7, B_4>;
/**
* @description
* Flatten a `Result` in a `Ok` value
*
* @see `Result.chain` - Chain another operation returning a `Result` over an `Ok` value
* @see `Result.catchError` - Chain another operation returning a `Result` over an `Ko` value
*
* @example
* ```ts
* const result: Result<Result<number, Error>, unknown> = pipe(
* Result.ok(1),
* Result.map(nb => nb >= 0
* ? Result.ok(nb + 1)
* : Result.ko(new Error('only positives'))
* )
* )
*
* const after: Result<number, Error | unknown> = Result.join(result)
* ```
*/
join: <A_8, E_5>(result: Result<Result<A_8, E_5>, E_5>) => Result<A_8, E_5>;
/**
* @description
* Chain another operation returning a `Result` over an `Ok` value
*
* @see `Result.catchError` - Chain another operation returning a `Result` over an `Ko` value
*
* @example
* ```ts
* const result: Result<number, Error | unknown> = pipe(
* Result.ok(1),
* Result.chain(nb => nb >= 0
* ? Result.ok(nb + 1)
* : Result.ko(new Error('only positives'))
* )
* )
* ```
*/
chain: <A_9, B_5, E_6 = unknown>(fn: (value: A_9) => Result<B_5, E_6>) => (result: Result<A_9, E_6>) => Result<B_5, E_6>;
/**
* @description
* Chain another operation returning a `Result` over an `Ko` value.
*
* @see `Result.chain` - Chain another operation returning a `Result` over an `Ok` value
*
* @example
* ```ts
* const result: Result<number, Error> = pipe(
* Result.ko(Err.of('some error', { name: 'SomeError' })),
* Result.catchError(err => pipe(err, Err.hasName('SomeError'))
* ? Result.ok(1)
* : Result.ko(err)
* )
* )
* ```
*/
catchError: <A_10, E_7 = unknown>(fn: (err: E_7) => Result<A_10, E_7>) => (result: Result<A_10, E_7>) => Result<A_10, E_7>;
/**
* @description
* Fold over a `Result`:
* - call `onOk` callback when the value is `Ok`
* - call `onKo` callback when the value is `Ko`
*
* @see `Result.get`
*
* @example
* ```ts
* const str = pipe(
* Result.ok(1),
* Result.fold(
* (value) => `Ok = ${value}`,
* (err: Error) => `An error occured: ${err.message}`
* )
* )
*
* expect(str).toBe(`Ok = 1`)
* ```
*/
fold: <R, A_11, E_8 = unknown>(onOk: (value: A_11) => R, onKo: (value: E_8) => R) => (result: Result<A_11, E_8>) => R;
/**
* @description
* Swap `Ok` and `Ko` value
*
* @example
* ```ts
* const result = pipe(
* Result.ok(1),
* Result.swap
* )
*
* expect(result).toEqual(Result.ko(1))
* ```
*/
swap: <A_12, E_9>(result: Result<A_12, E_9>) => Result<E_9, A_12>;
/**
* @description
* Try/catch an operation. The return value becomes the `Ok`, and the thrown value becomes the `Ko`
*
* @see `Result.fn`
*
* @example
* ```ts
* const divide = (a, b) => b === 0
* ? throwError(Err.of('cannot divide by zero'))
* : a / b
*
* const result = Result.tryCatch(() => divide(1, 0))
* ```
*/
tryCatch: <A_13>(fn: () => A_13) => Result<A_13, unknown>;
/**
* @description
* Resultify the given function, making it return a `Result` instead of throwing / returning a normal value
*
* @see `Result.tryCatch`
*
* @example
* ```ts
* const divide = (a, b) => b === 0
* ? throwError(Err.of('cannot divide by zero'))
* : a / b
*
* const [ok, ko] = pipe(
* [ [1,2], [3,0], [2,3], [4,0] ],
* Arr.map(Result.tryCatchFn(([a, b]) => divide(a, b))),
* Arr.separate
* )
* ```
*/
tryCatchFn: <Args extends any[], T_2>(fun: (...args: Args) => T_2) => (...args: Args) => Result<T_2, unknown>;
/**
* @description
* Takes a list of value as an input.
* Applies the function one by one, and returns the first succeeding `Result` or all errors
*
* @example
* ```ts
* const numbers = [-2, -3, 1, -7, -12, -6]
*
* const firstPositive = Result.unionBy(nb => nb >= 0
* ? Result.ok(nb)
* : Result.ko(`${nb} is negative`)
* )
*
* expect(pipe([-2, -3, 1, -7, -12], firstPositive)).toBe(1)
* expect(pipe([-2, -3, -7, -12], firstPositive)).toEqual([
* `-2 is negative`,
* `-3 is negative`,
* `-7 is negative`,
* `-12 is negative`
* ])
* ```
*/
unionBy: <T_3, A_14, E_10>(fn: (member: T_3, index: number) => Result<A_14, E_10>) => (members: NonEmptyArray<T_3>) => Result<A_14, E_10[]>;
/**
* @description
* Returns the first succeeding `Result` or all errors
*
* @example
* ```ts
* const results = [Result.ko(`-2 is negative`), Result.ko(`-3 is negative`), Result.ok(1)]
*
* expect(pipe(results, Result.union, Result.get)).toBe(1)
* ```
*/
union: <A_15, E_11>(members: NonEmptyArray<Result<A_15, E_11>>) => Result<A_15, E_11[]>;
/**
* @description
* Takes an object of values as an input and applies a function to all properties, to transform each property to a `Result`.
* If all properties are `Ok`, return an `Ok` with all values.
* If one or more properties are `Ko`, return the list of errors.
*
* @example
* ```ts
* const parseNbs = Result.structBy((prop, key) => {
* const nb = parseInt(prop)
* return isNaN(nb)
* ? Result.ko(Err.of(`Invalid number {value} at property {key}`, { value, key }))
* : Result.ok(nb)
* })
*
* const result1 = pipe(
* {
* a: "13",
* b: "24",
* d: "6"
* },
* parseNbs
* )
*
* expect(pipe(result1, Result.get)).toEqual({
* a: 13,
* b: 24,
* d: 6
* })
* ```
*/
structBy: <T_4, A_16, E_12>(fn: (prop: T_4, key: string) => Result<A_16, E_12>) => (props: Dict<T_4>) => Result<Dict<A_16>, E_12[]>;
/**
* @description
* Takes an object of results as an input.
* If all properties are `Ok`, return an `Ok` with all values.
* If one or more properties are `Ko`, return the list of errors.
*
* @example
* ```ts
* const all = pipe(
* {
* a: Result.ok(13),
* b: Result.ok(24),
* d: Result.ok(6)
* },
* Result.struct
* )
*
* expect(pipe(all, Result.get)).toEqual({
* a: 13,
* b: 24,
* d: 6
* })
* ```
*/
struct: <T_5 extends Dict<Result<any, unknown>>>(props: T_5) => Result<Struct<T_5>, StructErrors<T_5>[]>;
};
declare function filter<A, B extends A>(fn: Arr.Refinement<A, B>): (arr: A[]) => B[];
declare function filter<A>(fn: Arr.Predicate<A>): (arr: A[]) => A[];
declare function reject<A, B extends A>(fn: Arr.Refinement<A, B>): (arr: A[]) => InverseRefinement<A, B>[];
declare function reject<A>(fn: Arr.Predicate<A>): (arr: A[]) => A[];
declare function uniq<T>(arr: T[] | readonly T[]): T[];
declare function partition<A, B extends A>(fn: Refinement<A, B>): (arr: A[]) => [B[], InverseRefinement<A, B>[]];
declare function partition<A>(fn: Predicate<A>): (arr: A[]) => [A[], A[]];
declare type Arr<A = any> = Array<A>;
declare namespace Arr {
interface Predicate<A> {
(value: A, index: number): boolean;
}
interface Refinement<A, B extends A> {
(value: A, index: number): value is B;
}
}
/**
* @namespace Arr
*
* @description
*
* The `Arr` namespace contains all utilities related to Arrays.
*
* The utilities in this namespace are similar to the array utilities you can find in `underscore` or `lodash`.
*
* The big difference however is that they are pipeable, which means they can be chained like in the example below.
*
* ```ts
* const nb = pipe(
* [1,2,-3,4,-5],
* Arr.map(a => a * 2),
* Arr.filter(a => a >= 0),
* Arr.last
* )
*
* expect(nb).toBe(8)
* ```
*
* @see `NonEmptyArray` namespace, if you are handling arrays containing at least one element.
*
*/
declare const Arr: {
/**
* @description
* Create array from value
*/
of: <A>(value: A) => NonEmptyArray<A>;
/**
* @description
* Create array from an iterable
*/
from: <A_1>(value: Iterable<A_1> | A_1[]) => A_1[];
/**
* @description
* Get length of array
*/
length: <A_2>(arr: A_2[]) => number;
/**
* @description
* Check if the variable is an array
*/
isArray: (arr: unknown) => arr is unknown[];
/**
* @description
* Check if the array is empty
*/
isEmpty: <A_3>(arr: A_3[]) => arr is [];
/**
* @description
* Check if the array is non empty
*/
isNonEmpty: <A_4>(arr: A_4[]) => arr is NonEmptyArray<A_4>;
/**
* @description
* Returns the first value in the array.
* This function returns `undefined` when the array is empty.
*
* @example
* ```ts
* const first = pipe(
* [1,2,3,4],
* Arr.head
* )
*
* expect(first).toEqual(1)
* ```
*/
head: <A_5>(arr: A_5[]) => Option<A_5>;
/**
* @description
* Returns the last value in the array.
* This function returns `undefined` when the array is empty.
*
* @example
* ```ts
* const last = pipe(
* [1,2,3,4],
* Arr.last
* )
*
* expect(last).toEqual(4)
* ```
*/
last: <A_6>(arr: A_6[]) => Option<A_6>;
/**
* @description
* Calls a defined callback function on each element of an array, and returns an array that contains the results.
*
* @param fn - How to map each value
*
* @see `Arr.mapIndexed` if you need the index
*
* @example
* ```ts
* const nbs = pipe(
* [1,2,3],
* Arr.map(a => a + 1)
* )
*
* expect(nbs).toEqual([2,3,4])
* ```
*/
map: <A_7, B>(fn: (value: A_7) => B) => (arr: A_7[]) => B[];
/**
* @description
* Calls a defined callback function on each element of an array, and returns an array that contains the results.
*
* @param fn - How to map each value
*
* @see `Arr.map` if you don't need the index
*
* @example
* ```ts
* const nbs = pipe(
* [1,2],
* Arr.mapIndexed((a, index) => `index ${index} = ${a}`)
* )
*
* expect(nbs).toEqual([
* `index 0 = 1`,
* `index 1 = 2`
* ])
* ```
*/
mapIndexed: <A_8, B_1>(fn: (value: A_8, index: number, arr: A_8[]) => B_1) => (arr: A_8[]) => B_1[];
/**
* @description
* Chain over array.
*
* @param fn - Map and return new array from value
*
* @see `Arr.chainIndexed` if you need the index
* @see `Arr.map`
* @see `Arr.flatten`
*
* @example
* ```ts
* const array = pipe(
* [1,2,3],
* Arr.chain(value => [value, value])
* )
*
* expect(array).toEqual([1, 1, 2, 2, 3, 3])
* ```
*/
chain: <A_9, B_2>(fn: (value: A_9) => B_2[]) => (arr: A_9[]) => B_2[];
/**
* @description
* Chain over an array with an index.
*
* @param fn - Map and return new array from value
*
* @see `Arr.chain` if you don't need the index
* @see `Arr.map`
* @see `Arr.flatten`
*
* @example
* ```ts
* const nbs = pipe(
* [1,2],
* Arr.chainIndexed((a, index) => [a, index])
* )
*
* expect(nbs).toEqual([1,0,2,1])
* ```
*/
chainIndexed: <A_10, B_3>(fn: (value: A_10, index: number, arr: A_10[]) => B_3[]) => (arr: A_10[]) => B_3[];
/**
* @description
* Check if at least one element in the array matches the predicate
*
* @see `Arr.every`
*
* @example
* ```ts
* const childrenAges = [8, 11, 19]
* const hasAdult = pipe(childrenAges, Arr.some(age => age >= 18))
*
* expect(hasAdult).toBe(true)
* ```
*/
some: <A_11>(fn: (value: A_11) => boolean) => (arr: A_11[]) => boolean;
/**
* @description
* Check if all elements in the array match the predicate
*
* @see `Arr.some`
*
* @example
* ```ts
* const childrenAges = [8, 11, 19]
* const allAdults = pipe(childrenAges, Arr.every(age => age >= 18))
*
* expect(allAdults).toBe(false)
* ```
*/
every: <A_12>(fn: (value: A_12) => boolean) => (arr: A_12[]) => boolean;
/**
* @description
* Join array values by the given separator
*/
join: (sep?: string) => <A_13>(arr: A_13[]) => string;
/**
* @description
* Aggregate / accumulate all values in the array into a single value
*
* @example
* ```ts
* const nbs = [1,2,3,4]
* const total = pipe(
* nbs,
* Arr.reduce((a, b) => a + b, 0)
* )
* ```
*/
reduce: <A_14, B_4>(fn: (acc: B_4, current: A_14) => B_4, initial: B_4) => (arr: A_14[]) => B_4;
/**
* @description
* Filter items out of the array
*
* @param fn - Predicate or refinement on which items to remove from the array
*
* @see `Arr.filter`
* @see `Arr.filterMap`
*
* @example
* ```ts
* const array = pipe(
* [1,-2,3],
* Arr.reject(value => value >= 0)