-
Notifications
You must be signed in to change notification settings - Fork 2
/
compose.ts
74 lines (68 loc) · 1.47 KB
/
compose.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
/**
* @module Composition
*/
import type { UnaryFunction } from './types/function';
/**
* Makes a composition of functions from received arguments.
*/
export type Compose<
Arguments extends any[],
Functions extends any[] = []
> =
Arguments['length'] extends 0
? Functions
: Arguments extends [infer A, infer B]
? [...Functions, (arg: A) => B]
: Arguments extends [infer A, ...infer Rest, infer P, infer L]
? Compose<[A, ...Rest, P], [...Functions, (arg: P) => L]>
: []
/**
* Destructures a composition of functions into arguments.
*/
export type Decompose<
Functions extends UnaryFunction[],
Arguments extends any[] = []
> = Functions extends [(arg: infer Arg) => infer Return]
? [...Arguments, Arg, Return]
: Functions extends [...infer Rest extends UnaryFunction[], (arg: infer Arg) => any]
? Decompose<Rest, [...Arguments, Arg]>
: []
/**
* (B -> C) . (A -> B) = A -> C
*/
export default function compose<
A extends any[],
B,
C
> (
f: (arg: B) => C,
g: (...args: A) => B,
): (...args: A) => C
/**
* (B -> C) . (A -> B) = A -> C
*/
export default function compose<
A extends any[],
B,
C
> (
f: (arg: B) => C,
g: (...args: A) => B,
...args: A
): C
/**
* (B -> C) . (A -> B) = A -> C
*/
export default function compose<
A extends any[],
B,
C
> (
f: (arg: B) => C,
g: (...args: A) => B,
...maybeArgs: A
) {
return maybeArgs.length === 0
? (...args: A) => f(g(...args))
: f(g(...maybeArgs))
}