extra-function
Version:
Functions are one of the fundamental building blocks in JavaScript.
793 lines (792 loc) • 20.3 kB
TypeScript
/**
* unknown function type.
* @params args arguments
* @returns unknown value
*/ export type Function = (...args: unknown[]) => unknown;
/**
* Do nothing.
* @param _args arguments (ignored)
* @example
* ```javascript
* xfunction.NOOP(1, 2);
* // → undefined
*
* xfunction.NOOP('a', 'b');
* // → undefined
* ```
*/ export declare function NOOP(..._args: unknown[]): void;
/**
* Return false.
* @param _args arguments (ignored)
* @returns false.
* @example
* ```javascript
* xfunction.FALSE();
* // → false
* ```
*/ export declare function FALSE(..._args: unknown[]): false;
/**
* Return true.
* @param _args arguments (ignored)
* @returns true.
* @example
* ```javascript
* xfunction.TRUE();
* // → true
* ```
*/ export declare function TRUE(..._args: unknown[]): true;
/**
* Return the same (first) value.
* @param v a value
* @returns v
* @example
* ```javascript
* xfunction.IDENTITY(1);
* // → 1
*
* xfunction.IDENTITY('a');
* // → 'a'
* ```
*/ export declare function IDENTITY<T>(v: T): T;
/**
* Compare two values.
* @param a a value
* @param b another value
* @returns a<b: -1, a=b: 0, a>b: 1
* @example
* ```javascript
* xfunction.COMPARE(1, 2);
* // → -1
*
* xfunction.COMPARE(2, 1);
* // → 1
*
* xfunction.COMPARE(1, 1);
* // → 0
*/ export declare function COMPARE<T>(a: T, b: T): number;
/**
* Return the arguments passed as a array.
* @param args arguments
* @returns [...args]
* @example
* ```javascript
* xfunction.ARGUMENTS(1, 2);
* // → [1, 2]
*
* xfunction.ARGUMENTS('a', 'b');
* // → ['a', 'b']
* ```
*/ export declare function ARGUMENTS(...args: unknown[]): unknown[];
/**
* Get the name of a function.
* @param x a function
* @returns name
* @example
* ```javascript
* import {delay, debounce} from "jsr:@nodef/extra-function";
*
* xfunction.name(delay);
* // → 'delay'
*
* xfunction.name(debounce);
* // → 'debounce'
* ```
*/ export declare function name(x: Function): string;
/**
* Get the number of parameters of a function.
* @param x a function
* @returns |[p, q, ...]| | x(p, q, ...)
* @example
* ```javascript
* xfunction.length(() => 0);
* // → 0
*
* xfunction.length((x, y) => 0);
* // → 2
* ```
*/ export declare function length(x: Function): number;
export { length as arity };
/**
* Bind this-object, and optional prefix arguments to a function.
* @param x a function
* @param ths this object to bind
* @param prefix prefix arguments
* @returns (...args) => this.x(...prefix, ...args)
* @example
* ```javascript
* var array = [1];
* var fn = xfunction.bind(Array.prototype.push, array);
* fn(2, 3, 4); // push(2, 3, 4)
* array;
* // → [1, 2, 3, 4]
*
* var array = [1, 2, 3, 4];
* var fn = xfunction.bind(Array.prototype.splice, array, 1);
* fn(2); // splice(1, 2)
* array;
* // → [1, 4]
* ```
*/ export declare function bind(x: Function, ths: unknown, ...prefix: unknown[]): Function;
/**
* Invoke a function with specified this-object, and arguments provided individually.
* @param x a function
* @param ths this object to invoke with
* @param args arguments
* @returns this.x(...args)
* @example
* ```javascript
* var array = [1];
* xfunction.call(Array.prototype.push, array, 2, 3, 4); // push(2, 3, 4)
* array;
* // → [1, 2, 3, 4]
*
* var array = [1, 2, 3, 4];
* xfunction.call(Array.prototype.splice, array, 1, 2); // splice(1, 2)
* array;
* // → [1, 4]
* ```
*/ export declare function call(x: Function, ths?: unknown, ...args: unknown[]): unknown;
/**
* Invoke a function with specified this-object, and arguments provided as an array.
* @param x a function
* @param ths this object to invoke with
* @param args arguments array
* @returns this.x(...args)
* @example
* ```javascript
* var array = [1];
* xfunction.apply(Array.prototype.push, array, [2, 3, 4]); // push(2, 3, 4)
* array;
* // → [1, 2, 3, 4]
*
* var array = [1, 2, 3, 4];
* xfunction.apply(Array.prototype.splice, array, [1, 2]); // splice(1, 2)
* array;
* // → [1, 4]
* ```
*/ export declare function apply(x: Function, ths: unknown | undefined, args: unknown[]): unknown;
/**
* Check if value is a function.
* @param v a value
* @returns is function?
* @example
* ```javascript
* xfunction.is(Object.keys);
* // → true
*
* xfunction.is(() => 0);
* // → true
*
* xfunction.is(async () => 0);
* // → true
*
* xfunction.is(0);
* // → false
* ```
*/ export declare function is(v: unknown): v is Function;
/**
* Check if value is an async function.
* @param v a value
* @returns is async function?
* @example
* ```javascript
* xfunction.isAsync(async () => 0);
* // → true
*
* xfunction.isAsync(() => 0);
* // → false
* ```
*/ export declare function isAsync(v: unknown): boolean;
/**
* Check if value is a generator function.
* @param v a value
* @returns is generator function?
* @example
* ```javascript
* function* naturalNumbers() {
* for (var i=0;; ++i)
* yield i;
* }
*
* xfunction.isGenerator(naturalNumbers);
* // → true
*
* xfunction.isGenerator(() => 0);
* // → false
* ```
*/ export declare function isGenerator(v: unknown): v is GeneratorFunction;
/**
* Contextify a function by accepting the first parameter as this-object.
* @param x a function
* @returns (...args) => x(this, ...args)
* @example
* ```javascript
* function count(x, value) {
* var a = 0;
* for (var v of x)
* if (v===value) ++a;
* return a;
* }
*
* var fn = xfunction.contextify(count);
*
* fn.call([6, 3, 4, 3], 3);
* // → 2
*
* fn.call([6, 1, 4, 3], 3);
* // → 1
* ```
*/ export declare function contextify(x: Function): Function;
/**
* Decontextify a function by accepting this-object as the first argument.
* @param x a function
* @returns (this, ...args) => this.x(...args)
* @example
* ```javascript
* function count(value) {
* var a = 0;
* for (var v of this)
* if (v===value) ++a;
* return a;
* }
*
* var fn = xfunction.decontextify(count);
*
* fn([6, 3, 4, 3], 3);
* // → 2
*
* fn([6, 1, 4, 3], 3);
* // → 1
* ```
*/ export declare function decontextify(x: Function): Function;
/**
* Generate a result-negated version of a function.
* @param x a function
* @returns (...args) => !x(...args)
* @example
* ```javascript
* var fn = xfunction.negate(isFinite);
* fn(Infinity)
* // → true
* fn(1)
* // → false
*
* var fn = xfunction.negate(isNaN);
* fn(1);
* // → true
* fn(NaN);
* // → false
* ```
*/ export declare function negate(x: Function): Function;
/**
* Resolve arguments into a unique key.
* @param args arguments
* @returns unique key
*/ export type Resolver = (...args: unknown[]) => unknown;
/**
* Generate result-cached version of a function.
* @param x a function
* @param fr resolver ((...args) => unique key) [IDENTITY]
* @param cache result cache [Map()]
* @example
* ```javascript
* var calls = 0;
*
* function factorialRec(n: number) {
* if (n<=1) return 1;
* return n * factorialRec(n-1);
* }
*
* function factorial(n: number) {
* ++calls;
* return factorialRec(n);
* }
*
* var fn = xfunction.memoize(factorial);
* fn(3);
* // → 6
* fn(4);
* // → 24
* fn(5);
* // → 120
* fn(3);
* // → 6
* fn(4);
* // → 24
* fn(5);
* // → 120
* calls;
* // → 3
*
*
* var calls = 0;
*
* function hypot(x: number, y: number) {
* ++calls;
* return Math.hypot(x, y);
* }
*
* function resolver(x: number, y: number) {
* return 4093*y + x; // a hash
* }
*
* var fn = xfunction.memoize(hypot, resolver);
* fn(3, 4);
* // → 5
* fn(6, 8);
* // → 10
* fn(5, 12);
* // → 13
* fn(3, 4);
* // → 5
* fn(6, 8);
* // → 10
* fn(5, 12);
* // → 13
* calls;
* // → 3
* ```
*/ export declare function memoize(x: Function, fr?: Resolver | null, cache?: Map<unknown, unknown> | null): Function;
/**
* Generate a parameter-reversed version of a function.
* @param x a function
* @returns (p, q, ...) => x(..., q, p)
* @example
* ```javascript
* function divide(x, y) {
* return x/y;
* }
*
* var fn = xfunction.reverse(divide);
* fn(2, 4);
* // → 2
* fn(2, 6);
* // → 3
* fn(2, 8);
* // → 4
*
*
* var array = [1];
*
* function push(...args) {
* array.push(...args);
* }
*
* var fn = xfunction.reverse(push);
* fn(2, 3, 4); // push(2, 3, 4) in reverse order
* array;
* // → [1, 4, 3, 2]
* ```
*/ export declare function reverse(x: Function): Function;
export { reverse as flip };
/**
* Generate a (first) parameter-spreaded version of a function.
* @param x a function
* @returns (p, q, ...) => x([p, q, ...])
* @example
* ```javascript
* function sum(x: number[]) {
* var a = 0;
* for (var v of x)
* a += v;
* return a;
* }
*
* var fn = xfunction.spread(sum);
* fn(1, 2, 3); // sum([1, 2, 3])
* // → 6
*
*
* var array = [1];
*
* function concat(x: number[]) {
* return array.concat(x);
* }
*
* var fn = xfunction.spread(concat);
* fn(2, 3, 4); // concat([2, 3, 4])
* // → [1, 2, 3, 4]
* ```
*/ export declare function spread(x: Function): Function;
/**
* Generate a (first) parameter-collapsed version of a function.
* @param x a function
* @returns ([p, q, ...]) => x(p, q, ...)
* @example
* ```javascript
* var fn = xfunction.unspread(Math.min);
* fn([7, 4, 9]); // Math.min(7, 4, 9)
* // → 4
*
* var fn = xfunction.unspread((x, i, I) => x.slice(i, I));
* fn([[1, 2, 3, 4], 2]); // [1, 2, 3, 4].slice(2)
* // → [3, 4]
* ```
*/ export declare function unspread(x: Function): Function;
/**
* Attach prefix arguments to leftmost parameters of a function.
* @param x a function
* @param prefix prefix arguments
* @returns (...args) => x(...prefix, ...args)
* @example
* ```javascript
* var fn = xfunction.attach(Math.min, 100);
* fn(180, 130); // Math.min(100, 180, 130)
* // → 100
*
* var array = [1];
* var fn = xfunction.attach((...vs) => array.push(...vs), 10, 10);
* fn(1, 2, 3); // array.push(10, 10, 1, 2, 3)
* array;
* // → [1, 10, 10, 1, 2, 3]
* ```
*/ export declare function attach(x: Function, ...prefix: unknown[]): Function;
export { attach as partial };
/**
* Attach suffix arguments to rightmost parameters of a function.
* @param x a function
* @param suffix suffix arguments
* @returns (...args) => x(...args, ...suffix)
* @example
* ```javascript
* var fn = xfunction.attachRight(Math.min, 100);
* fn(180, 130); // Math.min(180, 130, 100)
* // → 100
*
* var array = [1];
* var fn = xfunction.attachRight((...vs) => array.push(...vs), 10, 10);
* fn(1, 2, 3); // array.push(1, 2, 3, 10, 10)
* array;
* // → [1, 1, 2, 3, 10, 10]
* ```
*/ export declare function attachRight(x: Function, ...suffix: unknown[]): Function;
export { attachRight as partialRight };
/**
* Compose functions together, in applicative order.
* @param xs functions (f, g)
* @returns (f o g), or f(g(x))
* @example
* ```javascript
* var fn = xfunction.compose(Math.sqrt, Math.abs);
* fn(-64); // Math.sqrt(Math.abs(-64))
* // → 8
*
* var fn = xfunction.compose(Math.sqrt, Math.min);
* fn(22, 9); // Math.sqrt(Math.min(22, 9))
* // → 3
* ```
*/ export declare function compose(...xs: Function[]): Function;
/**
* Compose functions together, such that result is piped forward.
* @param xs functions (f, g)
* @returns (f ▷ g), or g(f(x))
* @example
* ```javascript
* var fn = xfunction.composeRight(Math.abs, Math.sqrt);
* fn(-64); // Math.sqrt(Math.abs(-64))
* // → 8
*
* var fn = xfunction.composeRight(Math.min, Math.sqrt);
* fn(22, 9); // Math.sqrt(Math.min(22, 9))
* // → 3
* ```
*/ export declare function composeRight(...xs: Function[]): Function;
/**
* Generate curried version of a function.
* @param x a function
* @param n number of parameters [all]
* @returns (p)(q)(...) => x(p, q, ...)
* @example
* ```javascript
* var sub = (x: number, y: number) => x - y;
* var fn = xfunction.curry(sub);
* fn(2)(3); // sub(2, 3)
* // → -1
*
* var fn = xfunction.curry(Math.min, 3);
* fn(5)(8)(3); // Math.min(5, 8, 3)
* // → 3
* ```
*/ export declare function curry(x: Function, n?: number): Function;
/**
* Generate right-curried version of a function.
* @param x a function
* @param n number of parameters [all]
* @returns (p)(q)(...) => x(..., q, p)
* @example
* ```javascript
* var sub = (x: number, y: number) => x - y;
* var fn = xfunction.curryRight(sub);
* fn(2)(3); // sub(3, 2)
* // → 1
*
* var array = [1];
* var push2 = (x: number, y: number) => array.push(x, y);
* var fn = xfunction.curryRight(push2, 2);
* fn(2)(3); // push2(3, 2)
* array;
* // → [1, 3, 2]
* ```
*/ export declare function curryRight(x: Function, n?: number): Function;
/** Invocation control for time/rate-controlled functions. */ export interface InvocationControl {
/** Disable invoking of target function. */ clear: () => void;
/** Immediately invoke target function. */ flush: () => void;
}
/**
* Generate deferred version of a function, that executes after the current stack has cleared.
* @param x a function
* @returns (...args) => invocation control
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.defer(() => ++count);
* fn();
* fn();
* // `count` incremented after 0s
* // `count` incremented after 0s
* ```
*/ export declare function defer(x: Function): Function;
/**
* Generate delayed version of a function.
* @param x a function
* @param t delay time (ms)
* @returns (...args) => invocation control
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.delay(() => ++count, 500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* // `count` incremented after 0.5s
* // `count` incremented after 1.5s
*
*
* var count = 0;
* var fn = xfunction.delay(() => ++count, 500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* setTimeout(fn, 3000);
* // `count` incremented after 0.5s
* // `count` incremented after 1.5s
* // `count` incremented after 2.5s
* // `count` incremented after 3.5s
* ```
*/ export declare function delay(x: Function, t: number): Function;
/**
* Generate restricted-use version of a function.
* @param x a function
* @param start usable from
* @param end usable till (excluding) [-1 ⇒ end]
* @returns (...args) => x(...args) from [start:end] calls
* @example
* ```javascript
* var sum = 0;
* var add = (x: number) => sum += x;
* var fn = xfunction.restrict(add, 0, 4);
* for (var i=0; i<10; ++i)
* fn(i);
* sum; // 0 + 1 + 2 + 3
* // → 6
*
*
* var sum = 0;
* var add = (x: number) => sum += x;
* var fn = xfunction.restrict(add, 4, 8);
* for (var i=0; i<10; ++i)
* fn(i);
* sum; // 4 + 5 + 6 + 7
* // → 22
* ```
*/ export declare function restrict(x: Function, start: number, end?: number): Function;
/**
* Restrict a function to be used only once.
* @param x a function
* @returns (...args) => x(...args) from [0:1] calls
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.restrictOnce(x => ++count);
* for (var i=0; i<10; ++i)
* fn(i);
* count;
* // → 1
* ```
*/ export declare function restrictOnce(x: Function): Function;
export { restrictOnce as once };
/**
* Restrict a function to be used only upto a certain number of calls.
* @param x a function
* @param n number of calls upto which it is usable
* @returns (...args) => x(...args) from [0:n] calls
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.restrictBefore(x => ++count, 3);
* for (var i=0; i<10; ++i)
* fn(i);
* count;
* // → 3
* ```
*/ export declare function restrictBefore(x: Function, n: number): Function;
export { restrictBefore as before };
/**
* Restrict a function to be used only after a certain number of calls.
* @param x a function
* @param n number of calls after which it is usable
* @returns (...args) => x(...args) from [n:end] calls
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.restrictAfter(x => ++count, 3);
* for (var i=0; i<10; ++i)
* fn(i);
* count;
* // → 7
* ```
*/ export declare function restrictAfter(x: Function, n: number): Function;
export { restrictAfter as after };
/**
* Generate debounced version of a function.
* @param x a function
* @param t delay time (ms)
* @param T max delay time [-1 ⇒ none]
* @returns (...args) => invocation control
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.debounce(() => ++count, 1500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* setTimeout(fn, 4000);
* setTimeout(fn, 5000);
* // `count` incremented after 3.5s
* // `count` incremented after 6.5s
*
*
* var count = 0;
* var fn = xfunction.debounce(() => ++count, 1500);
* setTimeout(fn, 0);
* setTimeout(fn, 500);
* setTimeout(fn, 1000);
* setTimeout(fn, 1500);
* setTimeout(fn, 2000);
* setTimeout(fn, 4000);
* setTimeout(fn, 4500);
* setTimeout(fn, 5000);
* // `count` incremented after 3.5s
* // `count` incremented after 6.5s
*
*
* var count = 0;
* var fn = xfunction.debounce(() => ++count, 1500, 3500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* setTimeout(fn, 3000);
* setTimeout(fn, 4000);
* setTimeout(fn, 6000);
* // `count` incremented after 3.5s
* // `count` incremented after 5.5s
* // `count` incremented after 7.5s
* ```
*/ export declare function debounce(x: Function, t: number, T?: number): Function;
/**
* Generate leading-edge debounced version of a function.
* @param x a function
* @param t delay time (ms)
* @param T max delay time [-1 ⇒ none]
* @returns (...args) => invocation control
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.debounceEarly(() => ++count, 1500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* setTimeout(fn, 4000);
* setTimeout(fn, 5000);
* // `count` incremented after 0s
* // `count` incremented after 4s
*
*
* var count = 0;
* var fn = xfunction.debounceEarly(() => ++count, 1500);
* setTimeout(fn, 0);
* setTimeout(fn, 500);
* setTimeout(fn, 1000);
* setTimeout(fn, 1500);
* setTimeout(fn, 2000);
* setTimeout(fn, 4000);
* setTimeout(fn, 4500);
* setTimeout(fn, 5000);
* // `count` incremented after 0s
* // `count` incremented after 4s
*
*
* var count = 0;
* var fn = xfunction.debounceEarly(() => ++count, 1500, 3500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* setTimeout(fn, 3000);
* setTimeout(fn, 4000);
* setTimeout(fn, 6000);
* // `count` incremented after 0s
* // `count` incremented after 4s
* // `count` incremented after 6s
* ```
*/ export declare function debounceEarly(x: Function, t: number, T?: number): Function;
/**
* Generate throttled version of a function.
* @param x a function
* @param t wait time (ms)
* @returns (...args) => invocation control
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.throttle(() => ++count, 2500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* // `count` incremented after 2.5s
*
*
* var count = 0;
* var fn = xfunction.throttle(() => ++count, 2500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* setTimeout(fn, 3000);
* setTimeout(fn, 4000);
* // `count` incremented after 2.5s
* // `count` incremented after 5.5s
* ```
*/ export declare function throttle(x: Function, t: number): Function;
/**
* Generate leading-edge throttled version of a function.
* @param x a function
* @param t wait time (ms)
* @returns (...args) => invocation control
* @example
* ```javascript
* var count = 0;
* var fn = xfunction.throttleEarly(() => ++count, 2500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* // `count` incremented after 0s
*
*
* var count = 0;
* var fn = xfunction.throttleEarly(() => ++count, 2500);
* setTimeout(fn, 0);
* setTimeout(fn, 1000);
* setTimeout(fn, 2000);
* setTimeout(fn, 3000);
* setTimeout(fn, 4000);
* // `count` incremented after 0s
* // `count` incremented after 3s
* ```
*/ export declare function throttleEarly(x: Function, t: number): Function;