Closed
Description
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
The following minimal reproduction shows the reducer is incorrectly typed to accept AnyAction
interface A1 { type: 'A1' }
interface A2 { type: 'A2' }
type Action = A1 | A2
const reducerMap = {
s1: (s: number, a: Action) => 1,
s2: (s: number, a: Action) => 2,
}
const reducer = combineReducers(reducerMap)
// the reducer call works even though it should only accept actions A1 and A2.
reducer({ s1: 0, s2: 0 }, { type: 'blah' })
What is the expected behavior?
The action types should be inferred from the action. If the typings are changed to this it works:
type FunctionReturnType<T> = T extends (...args: any[]) => infer R ? R : never
type CombinedState<T extends object> = { [K in keyof T]: FunctionReturnType<T[K]> }
type ActionFromReducer<T extends object> = T[keyof T] extends (
state: any,
action: infer A,
...args: any[]
) => any
? A
: never
type ReducerReturnValue<T extends object> = (
state: CombinedState<T>,
action: ActionFromReducer<T>,
) => CombinedState<T>
export function combineReducers<T extends object>(reducers: T): ReducerReturnValue<T>
But this relies on conditional types which were added in typescript 2.8
.
Which versions of Redux, and which browser and OS are affected by this issue? Did this work in previous versions of Redux?
Redux 4.0.0