-
Notifications
You must be signed in to change notification settings - Fork 0
/
function.ts
91 lines (86 loc) · 2.31 KB
/
function.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
/**
* The Fn module provides utility methods for dealing with functions.
* @module Fn
*/
export type AnyFunction = (...args: any[]) => any
/**
* Curries a function so that it can be split into a function taking
* the first argument(s) and returning a function taking the next argument(s),
* down to N arguments.
*
* This enables partial application.
*
* Does not work with variable argument functions.
*
* @param { fn } function the function being curried
* @returns { fn } a new function which can be partially applied
*
* Usage:
* ```typescript
* function add(a, b) {
* return a + b
* }
*
* const curriedAdd = Fn.curry(add)
*
* const add9 = curriedAdd(9)
*
* add9(1) // 10
* curriedAdd(9, 1) // 10
* curriedAdd(9)(1) // 10
* ```
*/
export function curry(fn: AnyFunction): AnyFunction {
// Only functions are curryable
if (typeof fn !== 'function') {
throw new TypeError("Argument to Fn.curry must be a function")
}
return function curried(...args: any[]) {
switch(true) {
case args.length === 0: return undefined
case args.length >= fn.length: return fn(...args)
default: return (...args2: any[]) => curried(...args, ...args2)
}
}
}
/**
* Takes multiple functions in an argument list and returns a new function
* that will take the args of the first function and pipe the results of each
* function in order to produce the result.
*
* Can utilize Fn.curry to pass in partially applied functions.
*
* @param { ...fns } AnyFunction[] the functions being piped
* @returns { fn } a new piped function which
*
* Usage:
* ```typescript
* // Piping 2 functions
* function increment(n) { return n + 1 }
* function double(n) { return n * 2 }
*
* const incrementAndDouble = Fn.pipe(
* increment,
* double
* )
*
* incrementAndDouble(3) // 8
*
*
* // Utilize partial application
* function add(a, b) { return a + b }
*
* const doubleThenAdd3 = Fn.pipe(
* double,
* Fn.curry(add)(3)
* )
*
* doubleThenAdd3(2) // 7
* ```
*/
export function pipe(...fns: AnyFunction[]): AnyFunction {
if (fns == null || fns.length == 0 || fns.some(fn => typeof fn !== 'function')) {
throw new TypeError("All arguments to Fn.pipe must be functions")
}
return (arg) => fns.reduce((acc, fn) => fn(acc), arg)
}