fp-pack 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/fp-pack.umd.js +1 -1
- package/dist/fp-pack.umd.js.map +1 -1
- package/dist/implement/async/pipeAsync.d.ts +11 -0
- package/dist/implement/async/pipeAsync.d.ts.map +1 -1
- package/dist/implement/async/pipeAsync.mjs.map +1 -1
- package/dist/implement/async/pipeAsyncSideEffect.d.ts +11 -0
- package/dist/implement/async/pipeAsyncSideEffect.d.ts.map +1 -1
- package/dist/implement/async/pipeAsyncSideEffect.mjs.map +1 -1
- package/dist/implement/composition/compose.d.ts +25 -9
- package/dist/implement/composition/compose.d.ts.map +1 -1
- package/dist/implement/composition/compose.mjs.map +1 -1
- package/dist/implement/composition/compose.type-test.d.ts +35 -0
- package/dist/implement/composition/compose.type-test.d.ts.map +1 -0
- package/dist/implement/composition/compose.util.type-test.d.ts +31 -0
- package/dist/implement/composition/compose.util.type-test.d.ts.map +1 -0
- package/dist/implement/composition/index.d.ts +1 -0
- package/dist/implement/composition/index.d.ts.map +1 -1
- package/dist/implement/composition/pipe.type-test.d.ts +110 -0
- package/dist/implement/composition/pipe.type-test.d.ts.map +1 -1
- package/dist/implement/composition/pipe.util.type-test.d.ts +75 -0
- package/dist/implement/composition/pipe.util.type-test.d.ts.map +1 -0
- package/dist/implement/composition/tap0.d.ts +6 -0
- package/dist/implement/composition/tap0.d.ts.map +1 -0
- package/dist/implement/composition/tap0.mjs +9 -0
- package/dist/implement/composition/tap0.mjs.map +1 -0
- package/dist/index.mjs +230 -228
- package/dist/index.mjs.map +1 -1
- package/dist/skills/fp-pack/SKILL.md +2 -1
- package/dist/skills/fp-pack.md +2 -1
- package/package.json +1 -1
- package/src/implement/async/pipeAsync.ts +71 -0
- package/src/implement/async/pipeAsyncSideEffect.ts +74 -0
- package/src/implement/composition/compose.test.ts +14 -0
- package/src/implement/composition/compose.ts +133 -21
- package/src/implement/composition/compose.type-test.ts +109 -0
- package/src/implement/composition/compose.util.type-test.ts +128 -0
- package/src/implement/composition/index.ts +1 -0
- package/src/implement/composition/pipe.type-test.ts +252 -0
- package/src/implement/composition/pipe.util.type-test.ts +256 -0
- package/src/implement/composition/tap0.test.ts +16 -0
- package/src/implement/composition/tap0.ts +10 -0
|
@@ -5,6 +5,7 @@ import SideEffect, { isSideEffect } from '../composition/sideEffect';
|
|
|
5
5
|
type MaybeSideEffect<T> = T | SideEffect<any>;
|
|
6
6
|
type NonSideEffect<T> = Exclude<T, SideEffect<any>>;
|
|
7
7
|
type AsyncOrSync<A, R> = (a: A) => MaybeSideEffect<R> | Promise<MaybeSideEffect<R>>;
|
|
8
|
+
type ZeroFn<R> = () => MaybeSideEffect<R> | Promise<MaybeSideEffect<R>>;
|
|
8
9
|
type PipeInput<Fns extends AsyncOrSync<any, any>[]> = Fns extends [
|
|
9
10
|
AsyncOrSync<infer A, any>,
|
|
10
11
|
...AsyncOrSync<any, any>[]
|
|
@@ -29,6 +30,79 @@ type PipeAsyncSideEffectFrom<Fns extends [FromFn<any>, ...AsyncOrSync<any, any>[
|
|
|
29
30
|
function pipeAsyncSideEffect<Fns extends [FromFn<any>, ...AsyncOrSync<any, any>[]]>(
|
|
30
31
|
...funcs: Fns
|
|
31
32
|
): PipeAsyncSideEffectFrom<Fns>;
|
|
33
|
+
function pipeAsyncSideEffect<R>(ab: ZeroFn<R>): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
34
|
+
function pipeAsyncSideEffect<B, R>(
|
|
35
|
+
ab: ZeroFn<B>,
|
|
36
|
+
bc: AsyncOrSync<Awaited<B>, R>
|
|
37
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
38
|
+
function pipeAsyncSideEffect<B, C, R>(
|
|
39
|
+
ab: ZeroFn<B>,
|
|
40
|
+
bc: AsyncOrSync<Awaited<B>, C>,
|
|
41
|
+
cd: AsyncOrSync<Awaited<C>, R>
|
|
42
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
43
|
+
function pipeAsyncSideEffect<B, C, D, R>(
|
|
44
|
+
ab: ZeroFn<B>,
|
|
45
|
+
bc: AsyncOrSync<Awaited<B>, C>,
|
|
46
|
+
cd: AsyncOrSync<Awaited<C>, D>,
|
|
47
|
+
de: AsyncOrSync<Awaited<D>, R>
|
|
48
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
49
|
+
function pipeAsyncSideEffect<B, C, D, E, R>(
|
|
50
|
+
ab: ZeroFn<B>,
|
|
51
|
+
bc: AsyncOrSync<Awaited<B>, C>,
|
|
52
|
+
cd: AsyncOrSync<Awaited<C>, D>,
|
|
53
|
+
de: AsyncOrSync<Awaited<D>, E>,
|
|
54
|
+
ef: AsyncOrSync<Awaited<E>, R>
|
|
55
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
56
|
+
function pipeAsyncSideEffect<B, C, D, E, F, R>(
|
|
57
|
+
ab: ZeroFn<B>,
|
|
58
|
+
bc: AsyncOrSync<Awaited<B>, C>,
|
|
59
|
+
cd: AsyncOrSync<Awaited<C>, D>,
|
|
60
|
+
de: AsyncOrSync<Awaited<D>, E>,
|
|
61
|
+
ef: AsyncOrSync<Awaited<E>, F>,
|
|
62
|
+
fg: AsyncOrSync<Awaited<F>, R>
|
|
63
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
64
|
+
function pipeAsyncSideEffect<B, C, D, E, F, G, R>(
|
|
65
|
+
ab: ZeroFn<B>,
|
|
66
|
+
bc: AsyncOrSync<Awaited<B>, C>,
|
|
67
|
+
cd: AsyncOrSync<Awaited<C>, D>,
|
|
68
|
+
de: AsyncOrSync<Awaited<D>, E>,
|
|
69
|
+
ef: AsyncOrSync<Awaited<E>, F>,
|
|
70
|
+
fg: AsyncOrSync<Awaited<F>, G>,
|
|
71
|
+
gh: AsyncOrSync<Awaited<G>, R>
|
|
72
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
73
|
+
function pipeAsyncSideEffect<B, C, D, E, F, G, H, R>(
|
|
74
|
+
ab: ZeroFn<B>,
|
|
75
|
+
bc: AsyncOrSync<Awaited<B>, C>,
|
|
76
|
+
cd: AsyncOrSync<Awaited<C>, D>,
|
|
77
|
+
de: AsyncOrSync<Awaited<D>, E>,
|
|
78
|
+
ef: AsyncOrSync<Awaited<E>, F>,
|
|
79
|
+
fg: AsyncOrSync<Awaited<F>, G>,
|
|
80
|
+
gh: AsyncOrSync<Awaited<G>, H>,
|
|
81
|
+
hi: AsyncOrSync<Awaited<H>, R>
|
|
82
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
83
|
+
function pipeAsyncSideEffect<B, C, D, E, F, G, H, I, R>(
|
|
84
|
+
ab: ZeroFn<B>,
|
|
85
|
+
bc: AsyncOrSync<Awaited<B>, C>,
|
|
86
|
+
cd: AsyncOrSync<Awaited<C>, D>,
|
|
87
|
+
de: AsyncOrSync<Awaited<D>, E>,
|
|
88
|
+
ef: AsyncOrSync<Awaited<E>, F>,
|
|
89
|
+
fg: AsyncOrSync<Awaited<F>, G>,
|
|
90
|
+
gh: AsyncOrSync<Awaited<G>, H>,
|
|
91
|
+
hi: AsyncOrSync<Awaited<H>, I>,
|
|
92
|
+
ij: AsyncOrSync<Awaited<I>, R>
|
|
93
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
94
|
+
function pipeAsyncSideEffect<B, C, D, E, F, G, H, I, J, R>(
|
|
95
|
+
ab: ZeroFn<B>,
|
|
96
|
+
bc: AsyncOrSync<Awaited<B>, C>,
|
|
97
|
+
cd: AsyncOrSync<Awaited<C>, D>,
|
|
98
|
+
de: AsyncOrSync<Awaited<D>, E>,
|
|
99
|
+
ef: AsyncOrSync<Awaited<E>, F>,
|
|
100
|
+
fg: AsyncOrSync<Awaited<F>, G>,
|
|
101
|
+
gh: AsyncOrSync<Awaited<G>, H>,
|
|
102
|
+
hi: AsyncOrSync<Awaited<H>, I>,
|
|
103
|
+
ij: AsyncOrSync<Awaited<I>, J>,
|
|
104
|
+
jk: AsyncOrSync<Awaited<J>, R>
|
|
105
|
+
): () => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
32
106
|
function pipeAsyncSideEffect<A, R>(
|
|
33
107
|
ab: AsyncOrSync<A, R>
|
|
34
108
|
): (a: A | SideEffect<any>) => Promise<MaybeSideEffect<Awaited<R>>>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import compose from './compose';
|
|
3
|
+
import from from './from';
|
|
3
4
|
|
|
4
5
|
describe('compose', () => {
|
|
5
6
|
it('applies functions right-to-left', () => {
|
|
@@ -27,4 +28,17 @@ describe('compose', () => {
|
|
|
27
28
|
expect(fn(4)).toBe(16);
|
|
28
29
|
});
|
|
29
30
|
|
|
31
|
+
it('supports zero-arity tail functions', () => {
|
|
32
|
+
const addOne = (n: number) => n + 1;
|
|
33
|
+
const fn = compose(addOne, () => 2);
|
|
34
|
+
expect(fn()).toBe(3);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('supports from() as a constant source', () => {
|
|
38
|
+
const addOne = (n: number) => n + 1;
|
|
39
|
+
const fn = compose(addOne, from(2));
|
|
40
|
+
expect(fn()).toBe(3);
|
|
41
|
+
expect(fn(10)).toBe(3);
|
|
42
|
+
});
|
|
43
|
+
|
|
30
44
|
});
|
|
@@ -2,46 +2,158 @@
|
|
|
2
2
|
* compose - 함수를 우→좌로 합성
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type { FromFn } from './from';
|
|
6
|
+
|
|
5
7
|
type UnaryFn<A, R> = (a: A) => R;
|
|
8
|
+
type ZeroFn<R> = () => R;
|
|
6
9
|
type ComposeInput<Fns extends UnaryFn<any, any>[]> = Fns extends [...UnaryFn<any, any>[], UnaryFn<infer A, any>]
|
|
7
10
|
? A
|
|
8
11
|
: never;
|
|
9
|
-
type
|
|
10
|
-
?
|
|
12
|
+
type ComposeOutput<Fns extends UnaryFn<any, any>[]> = Fns extends [UnaryFn<any, infer R>]
|
|
13
|
+
? R
|
|
11
14
|
: Fns extends [UnaryFn<infer A, infer R>, ...infer Rest]
|
|
12
|
-
? Rest extends [UnaryFn<
|
|
13
|
-
?
|
|
14
|
-
?
|
|
15
|
+
? Rest extends [UnaryFn<any, any>, ...UnaryFn<any, any>[]]
|
|
16
|
+
? ComposeOutput<Rest> extends A
|
|
17
|
+
? R
|
|
15
18
|
: never
|
|
16
19
|
: never
|
|
17
20
|
: never;
|
|
18
|
-
type Compose<Fns extends UnaryFn<any, any>[]> = (input: ComposeInput<Fns>) =>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
>
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
type Compose<Fns extends UnaryFn<any, any>[]> = (input: ComposeInput<Fns>) => ComposeOutput<Fns>;
|
|
22
|
+
type ComposeFrom<Fns extends [...UnaryFn<any, any>[], FromFn<any>]> = (input?: ComposeInput<Fns>) => ComposeOutput<Fns>;
|
|
23
|
+
|
|
24
|
+
function compose<R>(ab: ZeroFn<R>): () => R;
|
|
25
|
+
function compose<B, R>(ab: UnaryFn<B, R>, bc: ZeroFn<B>): () => R;
|
|
26
|
+
function compose<C, B, R>(ab: UnaryFn<B, R>, bc: UnaryFn<C, B>, cd: ZeroFn<C>): () => R;
|
|
27
|
+
function compose<D, C, B, R>(ab: UnaryFn<B, R>, bc: UnaryFn<C, B>, cd: UnaryFn<D, C>, de: ZeroFn<D>): () => R;
|
|
28
|
+
function compose<E, D, C, B, R>(
|
|
29
|
+
ab: UnaryFn<B, R>,
|
|
30
|
+
bc: UnaryFn<C, B>,
|
|
31
|
+
cd: UnaryFn<D, C>,
|
|
32
|
+
de: UnaryFn<E, D>,
|
|
33
|
+
ef: ZeroFn<E>
|
|
34
|
+
): () => R;
|
|
35
|
+
function compose<F, E, D, C, B, R>(
|
|
36
|
+
ab: UnaryFn<B, R>,
|
|
37
|
+
bc: UnaryFn<C, B>,
|
|
38
|
+
cd: UnaryFn<D, C>,
|
|
39
|
+
de: UnaryFn<E, D>,
|
|
40
|
+
ef: UnaryFn<F, E>,
|
|
41
|
+
fg: ZeroFn<F>
|
|
42
|
+
): () => R;
|
|
43
|
+
function compose<G, F, E, D, C, B, R>(
|
|
44
|
+
ab: UnaryFn<B, R>,
|
|
45
|
+
bc: UnaryFn<C, B>,
|
|
46
|
+
cd: UnaryFn<D, C>,
|
|
47
|
+
de: UnaryFn<E, D>,
|
|
48
|
+
ef: UnaryFn<F, E>,
|
|
49
|
+
fg: UnaryFn<G, F>,
|
|
50
|
+
gh: ZeroFn<G>
|
|
51
|
+
): () => R;
|
|
52
|
+
function compose<H, G, F, E, D, C, B, R>(
|
|
53
|
+
ab: UnaryFn<B, R>,
|
|
54
|
+
bc: UnaryFn<C, B>,
|
|
55
|
+
cd: UnaryFn<D, C>,
|
|
56
|
+
de: UnaryFn<E, D>,
|
|
57
|
+
ef: UnaryFn<F, E>,
|
|
58
|
+
fg: UnaryFn<G, F>,
|
|
59
|
+
gh: UnaryFn<H, G>,
|
|
60
|
+
hi: ZeroFn<H>
|
|
61
|
+
): () => R;
|
|
62
|
+
function compose<I, H, G, F, E, D, C, B, R>(
|
|
63
|
+
ab: UnaryFn<B, R>,
|
|
64
|
+
bc: UnaryFn<C, B>,
|
|
65
|
+
cd: UnaryFn<D, C>,
|
|
66
|
+
de: UnaryFn<E, D>,
|
|
67
|
+
ef: UnaryFn<F, E>,
|
|
68
|
+
fg: UnaryFn<G, F>,
|
|
69
|
+
gh: UnaryFn<H, G>,
|
|
70
|
+
hi: UnaryFn<I, H>,
|
|
71
|
+
ij: ZeroFn<I>
|
|
72
|
+
): () => R;
|
|
73
|
+
function compose<J, I, H, G, F, E, D, C, B, R>(
|
|
74
|
+
ab: UnaryFn<B, R>,
|
|
75
|
+
bc: UnaryFn<C, B>,
|
|
76
|
+
cd: UnaryFn<D, C>,
|
|
77
|
+
de: UnaryFn<E, D>,
|
|
78
|
+
ef: UnaryFn<F, E>,
|
|
79
|
+
fg: UnaryFn<G, F>,
|
|
80
|
+
gh: UnaryFn<H, G>,
|
|
81
|
+
hi: UnaryFn<I, H>,
|
|
82
|
+
ij: UnaryFn<J, I>,
|
|
83
|
+
jk: ZeroFn<J>
|
|
84
|
+
): () => R;
|
|
24
85
|
|
|
86
|
+
function compose<Fns extends [...UnaryFn<any, any>[], FromFn<any>]>(...funcs: Fns): ComposeFrom<Fns>;
|
|
25
87
|
function compose<A, R>(ab: UnaryFn<A, R>): (a: A) => R;
|
|
26
|
-
function compose<A, B, R>(ab: UnaryFn<
|
|
27
|
-
function compose<A, B, C, R>(ab: UnaryFn<
|
|
88
|
+
function compose<A, B, R>(ab: UnaryFn<B, R>, bc: UnaryFn<A, B>): (a: A) => R;
|
|
89
|
+
function compose<A, B, C, R>(ab: UnaryFn<C, R>, bc: UnaryFn<B, C>, cd: UnaryFn<A, B>): (a: A) => R;
|
|
28
90
|
function compose<A, B, C, D, R>(
|
|
29
|
-
ab: UnaryFn<
|
|
30
|
-
bc: UnaryFn<
|
|
31
|
-
cd: UnaryFn<
|
|
32
|
-
de: UnaryFn<
|
|
91
|
+
ab: UnaryFn<D, R>,
|
|
92
|
+
bc: UnaryFn<C, D>,
|
|
93
|
+
cd: UnaryFn<B, C>,
|
|
94
|
+
de: UnaryFn<A, B>
|
|
33
95
|
): (a: A) => R;
|
|
34
96
|
function compose<A, B, C, D, E, R>(
|
|
35
|
-
ab: UnaryFn<
|
|
36
|
-
bc: UnaryFn<
|
|
97
|
+
ab: UnaryFn<E, R>,
|
|
98
|
+
bc: UnaryFn<D, E>,
|
|
37
99
|
cd: UnaryFn<C, D>,
|
|
100
|
+
de: UnaryFn<B, C>,
|
|
101
|
+
ef: UnaryFn<A, B>
|
|
102
|
+
): (a: A) => R;
|
|
103
|
+
function compose<A, B, C, D, E, F, R>(
|
|
104
|
+
ab: UnaryFn<F, R>,
|
|
105
|
+
bc: UnaryFn<E, F>,
|
|
106
|
+
cd: UnaryFn<D, E>,
|
|
107
|
+
de: UnaryFn<C, D>,
|
|
108
|
+
ef: UnaryFn<B, C>,
|
|
109
|
+
fg: UnaryFn<A, B>
|
|
110
|
+
): (a: A) => R;
|
|
111
|
+
function compose<A, B, C, D, E, F, G, R>(
|
|
112
|
+
ab: UnaryFn<G, R>,
|
|
113
|
+
bc: UnaryFn<F, G>,
|
|
114
|
+
cd: UnaryFn<E, F>,
|
|
38
115
|
de: UnaryFn<D, E>,
|
|
39
|
-
ef: UnaryFn<
|
|
116
|
+
ef: UnaryFn<C, D>,
|
|
117
|
+
fg: UnaryFn<B, C>,
|
|
118
|
+
gh: UnaryFn<A, B>
|
|
119
|
+
): (a: A) => R;
|
|
120
|
+
function compose<A, B, C, D, E, F, G, H, R>(
|
|
121
|
+
ab: UnaryFn<H, R>,
|
|
122
|
+
bc: UnaryFn<G, H>,
|
|
123
|
+
cd: UnaryFn<F, G>,
|
|
124
|
+
de: UnaryFn<E, F>,
|
|
125
|
+
ef: UnaryFn<D, E>,
|
|
126
|
+
fg: UnaryFn<C, D>,
|
|
127
|
+
gh: UnaryFn<B, C>,
|
|
128
|
+
hi: UnaryFn<A, B>
|
|
129
|
+
): (a: A) => R;
|
|
130
|
+
function compose<A, B, C, D, E, F, G, H, I, R>(
|
|
131
|
+
ab: UnaryFn<I, R>,
|
|
132
|
+
bc: UnaryFn<H, I>,
|
|
133
|
+
cd: UnaryFn<G, H>,
|
|
134
|
+
de: UnaryFn<F, G>,
|
|
135
|
+
ef: UnaryFn<E, F>,
|
|
136
|
+
fg: UnaryFn<D, E>,
|
|
137
|
+
gh: UnaryFn<C, D>,
|
|
138
|
+
hi: UnaryFn<B, C>,
|
|
139
|
+
ij: UnaryFn<A, B>
|
|
140
|
+
): (a: A) => R;
|
|
141
|
+
function compose<A, B, C, D, E, F, G, H, I, J, R>(
|
|
142
|
+
ab: UnaryFn<J, R>,
|
|
143
|
+
bc: UnaryFn<I, J>,
|
|
144
|
+
cd: UnaryFn<H, I>,
|
|
145
|
+
de: UnaryFn<G, H>,
|
|
146
|
+
ef: UnaryFn<F, G>,
|
|
147
|
+
fg: UnaryFn<E, F>,
|
|
148
|
+
gh: UnaryFn<D, E>,
|
|
149
|
+
hi: UnaryFn<C, D>,
|
|
150
|
+
ij: UnaryFn<B, C>,
|
|
151
|
+
jk: UnaryFn<A, B>
|
|
40
152
|
): (a: A) => R;
|
|
41
153
|
|
|
42
154
|
function compose<Fns extends [UnaryFn<any, any>, ...UnaryFn<any, any>[]]>(...funcs: Fns): Compose<Fns>;
|
|
43
155
|
function compose(...funcs: Array<UnaryFn<any, any>>): (input: any) => any;
|
|
44
|
-
function compose(...funcs: Array<(
|
|
156
|
+
function compose(...funcs: Array<(...args: any[]) => any>) {
|
|
45
157
|
return (value: any) => funcs.reduceRight((acc, fn) => fn(acc), value);
|
|
46
158
|
}
|
|
47
159
|
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import compose from './compose';
|
|
2
|
+
import from from './from';
|
|
3
|
+
|
|
4
|
+
type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
|
|
5
|
+
? true
|
|
6
|
+
: false;
|
|
7
|
+
type Expect<T extends true> = T;
|
|
8
|
+
|
|
9
|
+
export const pureCompose = compose(
|
|
10
|
+
(value: string) => `n:${value}`,
|
|
11
|
+
(value: number) => `${value}`,
|
|
12
|
+
(value: number) => value * 2,
|
|
13
|
+
(value: number) => value + 1
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
type PureComposeExpected = (input: number) => string;
|
|
17
|
+
export type ComposePureIsStrict = Expect<Equal<typeof pureCompose, PureComposeExpected>>;
|
|
18
|
+
|
|
19
|
+
export const pureComposeSix = compose(
|
|
20
|
+
(value: number) => `n:${value}`,
|
|
21
|
+
(value: number) => value + 1,
|
|
22
|
+
(value: string) => value.length,
|
|
23
|
+
(value: number) => `${value}`,
|
|
24
|
+
(value: number) => value * 2,
|
|
25
|
+
(value: number) => value + 1
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
type PureComposeSixExpected = (input: number) => string;
|
|
29
|
+
export type ComposePureSixIsStrict = Expect<Equal<typeof pureComposeSix, PureComposeSixExpected>>;
|
|
30
|
+
|
|
31
|
+
export const pureComposeTen = compose(
|
|
32
|
+
(value: string) => `n:${value}`,
|
|
33
|
+
(value: string) => value.padStart(4, '0'),
|
|
34
|
+
(value: number) => `${value}`,
|
|
35
|
+
(value: number) => value + 1,
|
|
36
|
+
(value: string) => value.length,
|
|
37
|
+
(value: string) => value.padStart(3, '0'),
|
|
38
|
+
(value: number) => `${value}`,
|
|
39
|
+
(value: number) => value * 2,
|
|
40
|
+
(value: number) => value + 1,
|
|
41
|
+
(value: number) => value + 1
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
type PureComposeTenExpected = (input: number) => string;
|
|
45
|
+
export type ComposePureTenIsStrict = Expect<Equal<typeof pureComposeTen, PureComposeTenExpected>>;
|
|
46
|
+
|
|
47
|
+
export const composeZero = compose(
|
|
48
|
+
(value: number) => value + 1,
|
|
49
|
+
(value: number) => value * 2,
|
|
50
|
+
() => 1
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
type ComposeZeroExpected = () => number;
|
|
54
|
+
export type ComposeZeroIsStrict = Expect<Equal<typeof composeZero, ComposeZeroExpected>>;
|
|
55
|
+
|
|
56
|
+
export const composeZeroValue = composeZero();
|
|
57
|
+
|
|
58
|
+
type ComposeZeroValueExpected = number;
|
|
59
|
+
export type ComposeZeroValueIsStrict = Expect<Equal<typeof composeZeroValue, ComposeZeroValueExpected>>;
|
|
60
|
+
|
|
61
|
+
export const composeFromNoInput = compose(from(1));
|
|
62
|
+
|
|
63
|
+
type ComposeFromNoInputExpected = (input?: unknown) => number;
|
|
64
|
+
export type ComposeFromNoInputIsStrict = Expect<Equal<typeof composeFromNoInput, ComposeFromNoInputExpected>>;
|
|
65
|
+
|
|
66
|
+
export const composeFromNoInputValue = composeFromNoInput();
|
|
67
|
+
|
|
68
|
+
type ComposeFromNoInputValueExpected = number;
|
|
69
|
+
export type ComposeFromNoInputValueIsStrict = Expect<
|
|
70
|
+
Equal<typeof composeFromNoInputValue, ComposeFromNoInputValueExpected>
|
|
71
|
+
>;
|
|
72
|
+
|
|
73
|
+
export const composeFromNoInputValueWithArg = composeFromNoInput('input');
|
|
74
|
+
|
|
75
|
+
type ComposeFromNoInputValueWithArgExpected = number;
|
|
76
|
+
export type ComposeFromNoInputValueWithArgIsStrict = Expect<
|
|
77
|
+
Equal<typeof composeFromNoInputValueWithArg, ComposeFromNoInputValueWithArgExpected>
|
|
78
|
+
>;
|
|
79
|
+
|
|
80
|
+
export const composeFromTen = compose(
|
|
81
|
+
(value: string) => `n:${value}`,
|
|
82
|
+
(value: string) => value.padStart(4, '0'),
|
|
83
|
+
(value: number) => `${value}`,
|
|
84
|
+
(value: number) => value + 1,
|
|
85
|
+
(value: string) => value.length,
|
|
86
|
+
(value: string) => value.padStart(3, '0'),
|
|
87
|
+
(value: number) => `${value}`,
|
|
88
|
+
(value: number) => value * 2,
|
|
89
|
+
(value: number) => value + 1,
|
|
90
|
+
from(1)
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
export const composeFromTenValue = composeFromTen('input');
|
|
94
|
+
|
|
95
|
+
type ComposeFromTenValueExpected = string;
|
|
96
|
+
export type ComposeFromTenValueIsStrict = Expect<Equal<typeof composeFromTenValue, ComposeFromTenValueExpected>>;
|
|
97
|
+
|
|
98
|
+
export const composeFromTenValueNoInput = composeFromTen();
|
|
99
|
+
|
|
100
|
+
type ComposeFromTenValueNoInputExpected = string;
|
|
101
|
+
export type ComposeFromTenValueNoInputIsStrict = Expect<
|
|
102
|
+
Equal<typeof composeFromTenValueNoInput, ComposeFromTenValueNoInputExpected>
|
|
103
|
+
>;
|
|
104
|
+
|
|
105
|
+
// Negative cases: input required when not using from/zero-arity.
|
|
106
|
+
// @ts-expect-error input required for unary compose
|
|
107
|
+
pureCompose();
|
|
108
|
+
// @ts-expect-error input required for direct compose call
|
|
109
|
+
compose((value: number) => value + 1)();
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import compose from './compose';
|
|
2
|
+
import filter from '../array/filter';
|
|
3
|
+
import flattenDeep from '../array/flattenDeep';
|
|
4
|
+
import map from '../array/map';
|
|
5
|
+
import sum from '../math/sum';
|
|
6
|
+
import gt from '../equality/gt';
|
|
7
|
+
import when from '../control/when';
|
|
8
|
+
import ifElse from '../control/ifElse';
|
|
9
|
+
import log from '../debug/log';
|
|
10
|
+
import tap from './tap';
|
|
11
|
+
import prop from '../object/prop';
|
|
12
|
+
import mergeAll from '../object/mergeAll';
|
|
13
|
+
import getOrElse from '../nullable/getOrElse';
|
|
14
|
+
import mapMaybe from '../nullable/mapMaybe';
|
|
15
|
+
import join from '../string/join';
|
|
16
|
+
import trim from '../string/trim';
|
|
17
|
+
import toUpper from '../string/toUpper';
|
|
18
|
+
import streamFilter from '../../stream/filter';
|
|
19
|
+
import streamMap from '../../stream/map';
|
|
20
|
+
import streamRange from '../../stream/range';
|
|
21
|
+
import streamReduce from '../../stream/reduce';
|
|
22
|
+
import streamToArray from '../../stream/toArray';
|
|
23
|
+
|
|
24
|
+
type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
|
|
25
|
+
? true
|
|
26
|
+
: false;
|
|
27
|
+
type Expect<T extends true> = T;
|
|
28
|
+
|
|
29
|
+
type User = {
|
|
30
|
+
name?: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type TagOwner = {
|
|
34
|
+
tags?: Array<string | null>;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type Config = {
|
|
38
|
+
value?: number;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const getName = prop('name') as (user: User) => string | undefined;
|
|
42
|
+
const getTags = prop('tags') as (owner: TagOwner) => Array<string | null> | undefined;
|
|
43
|
+
const mergeConfig = mergeAll as (configs: Config[]) => Config;
|
|
44
|
+
const getValue = prop('value') as (config: Config) => number | undefined;
|
|
45
|
+
const streamMapNumber = streamMap((value: number) => value + 1) as (iterable: Iterable<number>) => IterableIterator<number>;
|
|
46
|
+
const streamFilterNumber = streamFilter((value: number) => value > 1) as (
|
|
47
|
+
iterable: Iterable<number>
|
|
48
|
+
) => IterableIterator<number>;
|
|
49
|
+
const streamReduceNumber = streamReduce((acc: number, value: number) => acc + value, 0) as (
|
|
50
|
+
iterable: Iterable<number>
|
|
51
|
+
) => number;
|
|
52
|
+
const streamMapAsyncNumber = streamMap(async (value: number) => value + 1) as (
|
|
53
|
+
iterable: Iterable<number>
|
|
54
|
+
) => IterableIterator<Promise<number>>;
|
|
55
|
+
const whenPositive = when<number>(gt(0), (value) => value + 1);
|
|
56
|
+
|
|
57
|
+
export const composeArrayControlString = compose(
|
|
58
|
+
log('total'),
|
|
59
|
+
toUpper,
|
|
60
|
+
trim,
|
|
61
|
+
(value: number) => `${value}`,
|
|
62
|
+
when(gt(10), (value) => value + 1),
|
|
63
|
+
sum,
|
|
64
|
+
map((value: number) => value * 2),
|
|
65
|
+
filter(gt(1)),
|
|
66
|
+
flattenDeep<number>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
type ComposeArrayControlStringExpected = (input: any[]) => string;
|
|
70
|
+
export type ComposeArrayControlStringIsStrict = Expect<
|
|
71
|
+
Equal<typeof composeArrayControlString, ComposeArrayControlStringExpected>
|
|
72
|
+
>;
|
|
73
|
+
|
|
74
|
+
export const composeObjectNullableControl = compose(
|
|
75
|
+
tap((value: string) => value.length),
|
|
76
|
+
ifElse(
|
|
77
|
+
(value: string) => value.length > 0,
|
|
78
|
+
toUpper,
|
|
79
|
+
() => 'UNKNOWN'
|
|
80
|
+
),
|
|
81
|
+
getOrElse(''),
|
|
82
|
+
getName
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
type ComposeObjectNullableControlExpected = (input: User) => string;
|
|
86
|
+
export type ComposeObjectNullableControlIsStrict = Expect<
|
|
87
|
+
Equal<typeof composeObjectNullableControl, ComposeObjectNullableControlExpected>
|
|
88
|
+
>;
|
|
89
|
+
|
|
90
|
+
export const composeTags = compose(
|
|
91
|
+
join('|'),
|
|
92
|
+
map((tag: string) => tag.toUpperCase()),
|
|
93
|
+
mapMaybe((tag: string | null) => (tag ? tag.trim() : null)),
|
|
94
|
+
getOrElse<Array<string | null>>([]),
|
|
95
|
+
getTags
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
type ComposeTagsExpected = (input: TagOwner) => string;
|
|
99
|
+
export type ComposeTagsIsStrict = Expect<Equal<typeof composeTags, ComposeTagsExpected>>;
|
|
100
|
+
|
|
101
|
+
export const composeConfigValue = compose(
|
|
102
|
+
whenPositive,
|
|
103
|
+
getOrElse(0),
|
|
104
|
+
getValue,
|
|
105
|
+
mergeConfig
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
type ComposeConfigValueExpected = (input: Config[]) => number;
|
|
109
|
+
export type ComposeConfigValueIsStrict = Expect<Equal<typeof composeConfigValue, ComposeConfigValueExpected>>;
|
|
110
|
+
|
|
111
|
+
export const composeStreamSync = compose(
|
|
112
|
+
streamReduceNumber,
|
|
113
|
+
streamFilterNumber,
|
|
114
|
+
streamMapNumber,
|
|
115
|
+
(end: number) => streamRange(0, end)
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
type ComposeStreamSyncExpected = (input: number) => number;
|
|
119
|
+
export type ComposeStreamSyncIsStrict = Expect<Equal<typeof composeStreamSync, ComposeStreamSyncExpected>>;
|
|
120
|
+
|
|
121
|
+
export const composeStreamToArray = compose(
|
|
122
|
+
streamToArray,
|
|
123
|
+
streamMapAsyncNumber,
|
|
124
|
+
(end: number) => streamRange(0, end)
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
type ComposeStreamToArrayExpected = (input: number) => Promise<number[]>;
|
|
128
|
+
export type ComposeStreamToArrayIsStrict = Expect<Equal<typeof composeStreamToArray, ComposeStreamToArrayExpected>>;
|
|
@@ -12,6 +12,7 @@ export { default as constant } from './constant';
|
|
|
12
12
|
export { default as from } from './from';
|
|
13
13
|
export type { FromFn } from './from';
|
|
14
14
|
export { default as tap } from './tap';
|
|
15
|
+
export { default as tap0 } from './tap0';
|
|
15
16
|
export { default as once } from './once';
|
|
16
17
|
export { default as memoize } from './memoize';
|
|
17
18
|
export { default as SideEffect } from './sideEffect';
|