Creating Generic Slices
See original GitHub issueStemming from this thread
For better or worse a lot of our state has the same structure and so I’m trying to create helper where we can pass a name
, the initialState
and end up with a slice that contains most of everything we need.
I’m running into some issues with how to type it correctly. I’m pretty green to more advanced types so this could all be me not understanding how to type it. An example of what I’m trying to achieve:
export interface StateSlice<T = any> {
data: T
isFetching: boolean
receivedAt: number | null
error: boolean
errorMessage: string | null
errorCode: number | null
}
const requestStart: CaseReducer<StateSlice, PayloadAction> = (state: StateSlice) => {
state.isFetching = true
}
const requestSuccess: CaseReducer<StateSlice, PayloadAction> = (state, { payload }) => {
state.isFetching = false
state.receivedAt = Date.now()
state.error = false
state.errorMessage = null
state.errorCode = null
state.data = payload
}
export const createSlice = ({
name = '',
initialState,
reducers,
extraReducers = {}
}: {
name: string
initialState: StateSlice
reducers?: Record<string, CaseReducer<StateSlice, AnyAction>> // I've tried many different types here. Not final
}): Slice<StateSlice, AnyAction> => {
return createSliceToolkit({
name,
initialState,
reducers: {
requestSuccess,
requestStart,
...reducers
}
})
}
The issues I end up with:
-
When using this new
createSlice
and trying to pass it more reducers:const slice = createSlice({ name: 'generic/name', initialState, reducers: { updateSuccess: (state: StateSlice<Item[]>, { payload }: PayloadAction<Item>) => {} } })
This error happens:
Type ‘{ updateSuccess: (state: StateSlice<Item[]>, { payload }: WithPayload<Item, Action<string>>) => void; }’ is not assignable to type ‘Record<string, CaseReducer<StateSlice<any>, AnyAction>>’. Property ‘updateSuccess’ is incompatible with index signature. Type ‘(state: StateSlice<Item[]>, { payload }: WithPayload<Item, Action<string>>) => void’ is not assignable to type ‘CaseReducer<StateSlice<any>, AnyAction>’. Types of parameters ‘__1’ and ‘action’ are incompatible. Type ‘AnyAction’ is not assignable to type ‘WithPayload<Item, Action<string>>’. Property ‘payload’ is missing in type ‘AnyAction’ but required in type ‘{ payload: FeedPen; }’
-
When using actions:
const { requestStart, requestSuccess, updateSuccess } = bunkScoringSlice.actions dispatch(requestStart())
This error occurs:
const requestStart: void | WithTypeProperty<WithMatch<() => WithPayload<undefined, Action<string>>, string, undefined, never, never>, string> | WithTypeProperty<WithMatch<{ (payload?: undefined): WithPayload<undefined, Action<string>>; <PT extends unknown>(payload?: PT | undefined): WithPayload<PT, Action<string>>; }, string, unknown, never, never>, string>
This expression is not callable. Not all constituents of type ‘void | WithTypeProperty<WithMatch<() => WithPayload<undefined, Action<string>>, string, undefined, never, never>, string> | WithTypeProperty<WithMatch<{ (payload?: undefined): WithPayload<undefined, Action<string>>; <PT extends unknown>(payload?: PT | undefined): WithPayload<PT, Action<string>>; }, string, unknown, never, never>, string>’ are callable. Type ‘void’ has no call signatures.ts(2349)
All this to say, I’m stuck. Not sure if I’m missing some pretty obvious things but any help would be greatly appreciated!
Issue Analytics
- State:
- Created 4 years ago
- Reactions:4
- Comments:9 (6 by maintainers)
@MarceloAlves I’ve got a Draft PR over in #290 - if that lands, you could do it like this: https://github.com/reduxjs/redux-toolkit/pull/290/commits/b755f9d4ed6744a46ca8f05333d4731f7536196a
I guess that would solve your use case?
I was afraid of this.
This was actually my first approach (but I used the
CaseReducer
type) when the team asked if we could create the generator. It sounds like this might be the best way forward for now. At least it’ll greatly simplify the reducer part of each slice.No need to spend any more time on this! It’s the holidays after all 😃
We can stick with generic reducers and maybe revisit this in the future. Converting our older pieces of the store to
createSlice
and cleaning up where we can has already made a huge difference.Thanks for your time!