question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

how to properly type the reducer

See original GitHub issue

Related to https://github.com/supasate/connected-react-router/issues/173

versions:

  • connected-react-router 5.0.1
  • react 16.6.3
  • react-router 4.4.0-beta.6
  • redux 4.0.1
  • react-redux 5.1.1

I’m trying to declare my root state but I keep getting errors on History which I haven’t been able to resolve after hours.

reducer.ts

const persistConfig: PersistConfig = {
  key: "root",
  storage: localStorage,
};

export type RootState = ApiState &
  FirebaseState & {
    router: Reducer<RouterState, LocationChangeAction>;
  };

// connected-react-router v5 requires exporting a function accepting history
const createRootReducer: Reducer<RootState> = (history?: History) =>
  persistReducer(
    persistConfig,
    combineReducers({
      api,
      auth,
      firebase: persistReducer(
        {
          key: "firepersist",
          storage: localStorage,
          stateReconciler: hardSet,
        },
        firebaseReducer,
      ),
      router: connectRouter(history),
      ui,
      ...otherReducers,
    }),
  );

export default createRootReducer;

type check

$ tsc --project tsconfig.json
src/reducers/index.ts:52:7 - error TS2322: Type '(history?: History<any> | undefined) => Reducer<{ application: any; contact: any; faq: any; mediaList: any; releases: any; api: {}; auth: { isLoaded: boolean; isEmpty: boolean; userId: any; }; firebase: any; router: {}; ui: any; } & PersistPartial, AnyAction>' is not assignable to type 'Reducer<RootState, AnyAction>'.
  Types of parameters 'history' and 'state' are incompatible.
    Type 'RootState | undefined' is not assignable to type 'History<any> | undefined'.
      Type 'RootState' is not assignable to type 'History<any> | undefined'.
        Type 'RootState' is missing the following properties from type 'History<any>': length, action, location, push, and 7 more.

52 const createRootReducer: Reducer<RootState> = (history?: History) =>
         ~~~~~~~~~~~~~~~~~

src/reducers/index.ts:66:29 - error TS2345: Argument of type 'History<any> | undefined' is not assignable to parameter of type 'History<any>'.
  Type 'undefined' is not assignable to type 'History<any>'.

66       router: connectRouter(history),
                               ~~~~~~~


Found 2 errors.

error Command failed with exit code 1.

If I cannot solve this issue, I’ll change Reducer<RootState> → Reducer and persistReducer(…) → persistReducer(…) as any, but this wouldn’t be sane becore my exported RootState wouldn’t guarantee that the expected state is correct.

I understand that history is undefined at the beginning. Do you know of a way to say “that’s ok” this way ?

Issue Analytics

  • State:open
  • Created 5 years ago
  • Comments:5 (1 by maintainers)

github_iconTop GitHub Comments

7reactions
arnaud-zgcommented, May 22, 2019

I’m not sure if it’s the best solution, but it seems like combineReducers only want a function that returns a Reducer (given by redux). It works if I explicitly cast the result as Reducer like that:

router: connectRouter(history) as Reducer,
2reactions
favnacommented, May 31, 2019

The best way I ended up finding is to use the typesafe-actions library to property type both your actions and your reducer @kahurangitama.

You can find an example here: https://github.com/Favna/ReactTSDemo/blob/master/src/store

(note: also navigate to ProjectRoot/typings/typesafe-actions/index.d.ts which gets overwritten with the proper RootActions as per the lib’s requirement for typesafe reducer)

Edit: since the sample code above lacks connected-react-router use this as stand in for the index.ts file from the linked folder:

import {
  connectRouter, go, goBack, goForward,
  push, replace, RouterState
} from 'connected-react-router';
// other imports

const routerActions = {
  push: typeof push,
  replace: typeof replace,
  go: typeof go,
  goBack: typeof goBack,
  goForward: typeof goForward,
};

export type ApplicationState = Readonly<{
  router: RouterState;
  app: DemoState;
}>;

export function* rootSaga () {
  yield all([fork(demoSaga)]);
}

export const rootActions = {
  router: routerActions,
  counter: counterActions,
};

export type RootAction = ActionType<typeof rootActions>;

export default (history: History) => combineReducers<ApplicationState>({
  router: connectRouter(history),
  app: DemoReducer,
});
Read more comments on GitHub >

github_iconTop Results From Across the Web

Redux Fundamentals, Part 3: State, Actions, and Reducers
The official Redux Fundamentals tutorial: learn how reducers update state in response to actions.
Read more >
How to write clean reducers (and test them!)
When you're using reducer composition, combine your delegating cases at the bottom of your reducer. In the example of reducer composition, all ...
Read more >
How to Choose the right Reducer for your Paint Project
So you know that using a reducer with your paint is important. Great! That is half the battle. Now which temperature should you...
Read more >
Typing a useReducer React hook in TypeScript - Sumo Logic
We will see how to take advantage of TypeScript's discriminated unions to correctly type reducer's actions. Finally, we will introduce a ...
Read more >
Replace reducer proper typing - Stack Overflow
The need to apply types goes deeper because the property {injectPageReducer: (asyncReducer: Reducer) => void;} should know that the reducer is ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found