-
Notifications
You must be signed in to change notification settings - Fork 7
/
map.ts
118 lines (102 loc) · 2.89 KB
/
map.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// Copyright (c) 2020 Jozty. All rights reserved. MIT license.
import { isArray, isFunction, isObject } from './utils/is.ts';
import type {
Any,
Func,
FuncArr1,
InferElementType,
InferType,
Obj,
PH,
} from './utils/types.ts';
import curryN from './utils/curry_n.ts';
import { reduce } from './reduce.ts';
import { dispatch } from './utils/dispatch.ts';
import MapTransformer from './utils/Transformers/map.ts';
import { getFunctionLength } from './utils/get.ts';
// @types
type MapReturnType<F, R> = F extends unknown[] ? R[]
: F extends Func<infer A> ? Func<A, R>
: F extends Obj<unknown> ? Obj<R>
: never;
type MapInferType<F> = F extends Func ? Func
: F extends Obj<infer U> ? Obj<U>
: InferType<F>;
type MapInferElementType<F> = F extends Func ? Func
: F extends Obj<infer U> ? U
: InferElementType<F>;
type Map_2<T, R> = <F extends Obj<T> | Func<A, T> | T[], T, A extends Any[]>(
functor: F,
) => MapReturnType<F, R>;
type Map_1<F extends Obj<T> | Func<A, T> | T[], T, A extends Any[]> = <R>(
fn: FuncArr1<MapInferElementType<F>, R>,
) => MapReturnType<F, R>;
type Map =
& (<T, R>(fn: FuncArr1<T, R>) => Map_2<T, R>)
& (<F extends Obj<T> | Func<A, T> | T[], T, A extends Any[]>(
fn: PH,
functor: F,
) => Map_1<F, T, A>)
& (<F extends Obj<T> | Func<A, T> | T[], T, R, A extends Any[]>(
fn: FuncArr1<T, R>,
functor: F,
) => MapReturnType<F, R>);
function _functionMap<T, R, A extends Any[]>(
fn: FuncArr1<T, R>,
functor: Func<A, T>,
): Func {
return curryN(getFunctionLength(functor), function (
this: unknown,
...args: A
) {
return fn.call(this, functor.apply(this, args));
});
}
function _objectMap<T, R>(
func: FuncArr1<T, R>,
functor: Obj<T>,
): Obj<R> {
return reduce(
(acc: Obj<R>, key: string) => {
acc[key] = func(functor[key]);
return acc;
},
{},
Object.keys(functor),
);
}
function _arrayMap<T, R>(func: FuncArr1<T, R>, functor: T[]) {
const len = functor.length;
const result: R[] = new Array(len);
for (let i = 0; i < len; i++) {
result[i] = func(functor[i]);
}
return result;
}
function _map<F extends Obj<T> | Func<A, T> | T[], T, R, A extends Any[]>(
fn: FuncArr1<T, R>,
functor: F,
): MapReturnType<F, R> {
// @ts-ignore: TODO
if (isFunction(functor)) {
// @ts-ignore: TODO
return _functionMap(fn, functor) as MapReturnType<F, R>;
}
if (isArray(functor)) {
return _arrayMap(fn, functor) as MapReturnType<F, R>;
}
if (isObject(functor)) {
return _objectMap(fn, functor as Obj<T>) as MapReturnType<F, R>;
}
throw new TypeError(
'Functor can be only array, object or a transformer',
);
}
const dispatchedMap = dispatch(MapTransformer, _map);
/**
* Applies `fn` to each of `functor`'s value
* and returns functor of same shape
*
* Acts as a transducer if a transformer is given in `functor`.
*/
export const map = curryN(2, dispatchedMap) as Map;