-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmutableFn.ts
72 lines (59 loc) · 1.67 KB
/
mutableFn.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
import { MaybeMutable, Mutable } from './types';
import mutable from './mutable';
import isMutable from './isMutable';
import { listen } from './eventBus';
type MaybeMutableTuple<Input extends [...any[]]> = Input extends [
infer First,
...infer Rest,
]
? [MaybeMutable<First>, ...MaybeMutableTuple<Rest>]
: Input;
type MaybeMutableParams<Params extends any[]> = {
[K in keyof Params]: Params[K] extends Mutable<any>
? Params[K]
: Params[K] extends Record<string, unknown>
? MaybeMutable<{
[OK in keyof Params[K]]: MaybeMutable<Params[K][OK]>;
}>
: Params[K] extends [...any[]]
? MaybeMutable<MaybeMutableTuple<Params[K]>>
: MaybeMutable<Params[K]>;
};
export function mutableFn<Params extends any[], ReturnType>(
actionFn: (...params: Params) => ReturnType,
) {
type CallParams = MaybeMutableParams<Params>;
return (...params: CallParams): Mutable<ReturnType> => {
const pureParams = [] as unknown as Params;
params.forEach((arg, i) => {
if (isMutable(arg)) {
listen(arg, (newVal) => {
pureParams[i] = newVal;
rerun();
});
pureParams[i] = arg.value;
} else if (typeof arg === 'object') {
pureParams[i] = Array.isArray(arg) ? [] : {};
Object.entries(arg).forEach(([key, item]) => {
if (isMutable(item)) {
listen(item, (newVal) => {
pureParams[i][key] = newVal;
rerun();
});
pureParams[i][key] = item.value;
} else {
pureParams[i][key] = item;
}
});
} else {
pureParams[i] = arg;
}
});
let out = mutable(actionFn.apply(null, pureParams));
function rerun() {
out.value = actionFn.apply(null, pureParams);
}
return out;
};
}
export default mutableFn;