Hello,
I'm trying to create a generic reducer with createSlice, I cannot figure out the type to use for the action parameter to allow actions with or without a payload
import { createSlice } from '@reduxjs/toolkit'
interface State {
loading: boolean
item?: any
errors?: any
payload?: any
}
const initialState: State = {
loading: false,
}
export const slice = createSlice({
name: 'myslice',
initialState,
reducers: {
// How to type action for allowing readRequest() or readRequest(somePayload)
readRequest: (state: State, action: any) => {
state.loading = true
if ('payload' in action) {
state.payload = action.payload
}
},
readSuccess: (state: State, action: any) => {
state.loading = false
if ('payload' in action) {
state.payload = action.payload
}
},
},
})
const { actions } = slice
// error readSuccess is expecting 1 argument
actions.readSuccess()
In this example readSuccess() is expecting 1 argument event if its type is
ActionCreatorWithNonInferrablePayload<string> | ActionCreatorWithoutPayload<string>
Hmm. Does something like:
readRequest(state, action: PayloadAction<string | void>) {}
work for you?
readRequest(state, action: PayloadAction<string | undefined>){}
is what you're looking for.
With
readRequest(state, action: PayloadAction<string | void>) {}
readRequest is expecting 0 arguments (cannot pass a string)
with
readRequest(state, action: PayloadAction<string | undefined>){}
readRequest can accept a string or nothing but what I'm looking is PayloadAction<any>.
But with any the payload is mandatory.
What seems to work is to use
type anything =
| number
| string
| boolean
| bigint
| symbol
| null
| object
| undefined;
readRequest(state, action: PayloadAction<anything>){}
It does not seems right since anything is basically any.
Yeah, that's essentially a design decision. We had to decide if PayloadAction<any> results in either a payload action creator that requires one argument that could be anything, or requires one optional argument.
Since we can't support both, the first one seemed the more common use case - so for your use case you'll have to use that workaround you have there.
My question here is: are you sure you want to write something like that at all? That sounds like you're giving up all type-safety down the road, at which point the question would be why you're using TS at all.
Maybe something going in the direction of wrapping createSlice with a generic might help you keep type-safety.
Thanks @phryneas for the answer, I understand the design decision.
Indeed it looks like a TS anti-pattern, I was trying to understand the type decisions around actions, in the end I think I'll use a proper type for action payloads.
Most helpful comment
is what you're looking for.