redux-toolkit: createReducer does not infer action types
When I create a reducer, the action type does not get inferred from the action. Example:
const myAction = createAction<boolean>('my/action')
const reducer = createReducer(false, {
// action is of type "any" (and then so is the payload)
[myAction.type](state, action) {
return action.payload
},
})
I am currently rolling my own setup, where I’ve got this type of inference working. Though I’m using the payload rather than the whole action object as a parameter for my callbacks.
In my case, I have to type the action like this through an extra function invocation, though I’m not sure how necessary this is.
const action = createAction('my/action')<boolean>()
I don’t pretend to understand how all of this works, but maybe someone can figure out a way to get the best of both worlds? What follows is pretty much my whole setup for this.
import { produce, Draft } from 'immer'
import { EmptyAction, PayloadAction, createAction as createTypesafeAction } } from 'typesafe-actions'
export default function createAction<T extends string>(type: T) {
return function<P extends any = undefined>() {
return Object.assign(createTypesafeAction(type)<P>(), { type })
}
}
export type Action<T extends string = string, P = never> = EmptyAction<T> | PayloadAction<T, P>
export type Producer<S, A extends Action> = A extends PayloadAction<any, infer P>
? (draft: Draft<S>, payload: P) => void | S
: (draft: Draft<S>) => void | S
export type Producers<S, A extends Action> = A extends PayloadAction<any, any>
? { [T in A['type']]: Producer<S, A> }
: { [T in A['type']]: Producer<S, A> }
export default function createReducer<S, A extends Action>(defaultState: S, producers: Producers<S, A>) {
return function reducer(state = defaultState, action: A) {
return produce(state, draft => {
if (action.type in producers) {
return producers[action.type](draft, action.payload)
}
})
}
}
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 1
- Comments: 17 (5 by maintainers)
@Glinkis you could do this:
You can, but it might be a bit too clever. If/else ishould be more idiomatic in that case.