piotrwitek / typesafe-actions

Typesafe utilities for "action-creators" in Redux / Flux Architecture
https://codesandbox.io/s/github/piotrwitek/typesafe-actions/tree/master/codesandbox
MIT License
2.41k stars 98 forks source link

feat: typed combineReducers function #20

Closed CzBuCHi closed 6 years ago

CzBuCHi commented 6 years ago

added typed version of combineReducers method from 'redux', usage is the same as original method, except mine has two required generics type parameters - state type and actions type

usage:

// same old story ...
import { createAction, combineReducers } from "typesafe-actions";
import { $call } from "utility-types";

const actions = {
  actionA: createAction("A", (val: string) => ({ type: "A", payload: val })),
  actionB: createAction("B", (val: number) => ({ type: "B", payload: val })),
};

const returnsOfActions = Object.values(actions).map($call);
type Actions = typeof returnsOfActions[number];

function reducerA(state: string, action: Actions): string { ... }
function reducerB(state: number, action: Actions): number { ... }

type State: { a: string, b: number };

// verbose way:
const reducer = (state: State, action: Actions) => {
  return {
    a: reducerA(state.a, action),
    b: reducerB(state.b, action),
  };
};

// 'redux' way:
const reducer = combineReducers<State, Actions>({
  a: reducerA,
  b: reducerB,
});

original method throws this error (reason for this PR):

message: 'Argument of type '{ a: (state: number | undefined, action: { type: "A"; payload: string; } | { type: "B"; payload: ...' is not assignable to parameter of type 'ReducersMapObject'.
  Property 'a' is incompatible with index signature.
    Type '(state: number | undefined, action: { type: "A"; payload: string; } | { type: "B"; payload: strin...' is not assignable to type 'Reducer<any>'.
      Types of parameters 'action' and 'action' are incompatible.
        Type 'AnyAction' is not assignable to type '{ type: "A"; payload: string; } | { type: "B"; payload: string; }'.
          Type 'AnyAction' is not assignable to type '{ type: "B"; payload: string; }'.
            Property 'payload' is missing in type 'AnyAction'.'

PS: edit in package.json is required on my machine (tslint fails otherwise)

piotrwitek commented 6 years ago

Hi @CzBuCHi, Thanks for this PR, I'm in the middle of finishing a design for a new API for this library, I'll come back to this issue in two days.

CzBuCHi commented 6 years ago

I wait then ....

btw: After some more learning about redux i found, that redux's createStore method has same issue (cast to AnyAction)

fixed that too with this: (again calls original method underhood)

function createStore<S, A>(reducer: Reducer<S, A>, enhancer?: StoreEnhancer<S>): Store<S>;
function createStore<S, A>(reducer: Reducer<S, A>, initialState: S, enhancer?: StoreEnhancer<S>): Store<S>;

but that got me thinking, that both these changes should be in redux itself (technically these are only typescript shenanigans with no changes in js) and not here ...

Anyway i wait for your input on this ....

piotrwitek commented 6 years ago

Perhaps you're using redux v3? If yes then read this section please: https://github.com/piotrwitek/react-redux-typescript-guide#type-definitions-for-react--redux

And in that case yes, this doesn't have anything to do with this lib.

CzBuCHi commented 6 years ago

yup ... im on wrong repo :) ... thanks for your time ...