-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
55 lines (42 loc) · 1.94 KB
/
index.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
export type Action = { type: string; };
export type Reducer<TState> = (prevState: TState | undefined, action: Action) => TState;
export interface Handler<TState, TPayload> {
(state: TState, payload: TPayload): TState;
}
export interface HandlerMap<TState> {
[actionType: string]: Handler<TState, any>;
}
export interface StatePipe<TState, TParent> {
diveIn(parent: TParent, action: Action): TState;
bubbleUp(parent: TParent, newChild: TState): TParent;
}
export interface RootNode<TState> {
handlers: HandlerMap<TState>;
children?: ChildNode<any>[];
}
export interface ChildNode<TState> extends RootNode<TState> {
statePipe: StatePipe<TState, any>;
}
export function createReducer<TState>(handlers: HandlerMap<TState>, initialState: TState): Reducer<TState> {
return (state: TState = initialState, action: Action): TState => {
const handler = handlers[action.type];
return handler ? handler(state, action) : state;
};
}
function bubbleHandler<TChild, TParent>(handler: Handler<TChild, any>, { diveIn, bubbleUp }: StatePipe<TChild, TParent>): Handler<TParent, any> {
return (state: TParent, action: Action): TParent => bubbleUp(state, handler(diveIn(state, action), action));
}
export function flattenNode<TState>(node: RootNode<TState>): HandlerMap<TState> {
const result: HandlerMap<TState> = { ...(node.handlers || {}) };
for (const child of node.children || []) {
const childrenHandlers: HandlerMap<any> = (child.children || []).reduce((handlers, child) => Object.assign(handlers, flattenNode(child)), {});
const combined = { ...child.handlers, ...childrenHandlers };
for (const actionType of Object.keys(combined)) {
result[actionType] = bubbleHandler(combined[actionType], child.statePipe);
}
}
return result;
}
export function createHandlers<T>(reducer: Reducer<T>, actionTypes: string[]): HandlerMap<T> {
return actionTypes.reduce((handlers, action) => Object.assign(handlers, { [action]: reducer }), {});
}