-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathreduce-exercise-state.ts
61 lines (57 loc) · 2.28 KB
/
reduce-exercise-state.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
import { freeze, produce } from 'immer';
import type { ExerciseState } from '../state';
import type { Mutable } from '../utils';
import type { ExerciseAction } from './action-reducers';
import { getExerciseActionTypeDictionary } from './action-reducers';
const exerciseActionTypeDictionary = getExerciseActionTypeDictionary();
/**
* A pure reducer function that applies the action on the state without mutating it.
* @param state The current state (immutable)
* @param action The action to apply on the current state
* @throws {ReducerError} if the action is not applicable on the current state
* @returns the new state
*/
export function reduceExerciseState(
state: ExerciseState,
action: ExerciseAction
): ExerciseState {
// Make sure that the state isn't mutated in the reducer (short circuits if the state is already frozen)
freeze(state, true);
// use immer to convert mutating operations to immutable ones (https://immerjs.github.io/immer/produce)
return produce(state, (draftState) => applyAction(draftState, action));
}
/**
* Applies the action on the state by mutating it.
* @param draftState The current state (mutable)
* @param action The action to apply on the current state
* @throws {ReducerError} if the action is not applicable on the current state
* @returns the new state
*/
export function applyAction(
draftState: Mutable<ExerciseState>,
action: ExerciseAction
) {
// Make sure that the action isn't mutated in the reducer (short circuits if the action is already frozen)
freeze(action, true);
return exerciseActionTypeDictionary[action.type].reducer(
draftState,
// typescript doesn't narrow action and the reducer to the correct ones based on action.type
action as any
);
}
/**
* @param actions all the actions that were applied to the {@link initialState} to get to the present state
* @returns the state after applying all the actions
*/
export function applyAllActions(
initialState: ExerciseState,
actions: readonly ExerciseAction[]
): ExerciseState {
// TODO: find a heuristic for whether using produce or deepCloning it
// Default is produce
return produce(initialState, (draftState) => {
for (const action of actions) {
applyAction(draftState, action);
}
});
}