@reduxjs/toolkit
Version:
The official, opinionated, batteries-included toolset for efficient Redux development
42 lines (37 loc) • 1.29 kB
text/typescript
import createNextState, { isDraft } from 'immer'
import { EntityState } from './models'
import { PayloadAction, isFSA } from '../createAction'
export function createStateOperator<V, R>(
mutator: (arg: R, state: EntityState<V>) => void
) {
return function operation<S extends EntityState<V>>(
state: S,
arg: R | PayloadAction<R>
): S {
function isPayloadActionArgument(
arg: R | PayloadAction<R>
): arg is PayloadAction<R> {
return isFSA(arg)
}
const runMutator = (draft: EntityState<V>) => {
if (isPayloadActionArgument(arg)) {
mutator(arg.payload, draft)
} else {
mutator(arg, draft)
}
}
if (isDraft(state)) {
// we must already be inside a `createNextState` call, likely because
// this is being wrapped in `createReducer` or `createSlice`.
// It's safe to just pass the draft to the mutator.
runMutator(state)
// since it's a draft, we'll just return it
return state
} else {
// @ts-ignore createNextState() produces an Immutable<Draft<S>> rather
// than an Immutable<S>, and TypeScript cannot find out how to reconcile
// these two types.
return createNextState(state, runMutator)
}
}
}