-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tips on how to avoid circular dependencies with the module pattern and inferring RootState
from rootReducer
?
#154
Comments
You can define Something like that in a
Then for example when you define a selector :
There is an example of that in playground project. I use that in my project and it works well. Hope it will help ! |
@thomasvanlankveld Did it help you ? |
@chawax Thanks for the swift reply! I tried the suggestion in two different ways. When I try it with import statements outside the // src/App/core/RootTypes.d.ts
import { StateType } from 'typesafe-actions';
import { rootReducer } from '../store/rootReducer';
import { PostActions } from '../../Posts/core';
import { ServerAPI } from '../../ServerAPI';
declare module "RootTypes" {
export type RootAction = PostActions;
export type RootState = StateType<typeof rootReducer>;
export type Services = { serverAPI: ServerAPI };
} The following then yields // src/App/store/setupStore.ts
import { Services, RootState, RootAction } from 'RootTypes'; When I move the imports into the For now I just made RootState an explicit combination of the slice states, since the guide recommends making all of these explicit anyway. My slice state types are in various // src/App/core/types.ts
import { PostActions, PostsState, AuthorsState } from "../../Posts/core";
import { UsersState } from "../../Users/core";
import { ServerAPI } from "../../ServerAPI";
export type RootAction = PostActions;
export type RootState = Readonly<{
posts: PostsState;
authors: AuthorsState;
users: UsersState;
}>;
export type Services = { serverAPI: ServerAPI };
// src/App/data/rootReducer.ts
import { combineReducers, Reducer } from 'redux';
import { RootAction, RootState } from '../core';
import { postsReducer, authorsReducer } from '../../Posts/data';
import { usersReducer } from '../../Users/data';
export const rootReducer: Reducer<RootState, RootAction> = combineReducers({
posts: postsReducer,
authors: authorsReducer,
users: usersReducer
}); This setup works well so far. It requires very little extra (one might say 'redundant') typing, with the added benefits of making sure the state tree is very easy to explore with VSC, and that it is Edit: I guess I could maybe still use ambient modules to get absolute imports for all of these things... |
I'm closing this as it is an old and solved issue and the working example solution was also linked by @chawax: https://github.com/piotrwitek/react-redux-typescript-guide/blob/master/playground/src/store/types.d.ts Btw. the correct solution was producing any for you because you were not following the example precisely, just use the exact same syntax as in the example and you'll be good. |
Ahhhh thanks! The following does work: declare module 'RootTypes' {
import { StateType } from "typesafe-actions";
export type RootAction = import('../../Posts/core').PostActions;
export type RootState = StateType<typeof import('../store/rootReducer').rootReducer>;
export type Services = { serverAPI: import('../../ServerAPI').ServerAPI };
} @piotrwitek In this setup, RootState is no longer |
Glad it worked! Readonly doesn't change anything right now because it's not recursive anyway, now from 3.4 we have new syntax for type assertion Perhaps you could even create a ticket for it in "typesafe-actions" repo if you want. |
That sounds promising! In the meantime, the following seems to do the trick: import { DeepReadonly } from "utility-types";
export type RootState = DeepReadonly<
StateType<typeof import('../store/rootReducer').rootReducer>
>; |
@thomasvanlankveld yeah definitely, that's another option! |
@piotrwitek @thomasvanlankveld @chawax Sorry for reviving this thread, but I had to make sure it's abundantly clear how grateful I am for this thread. You've resolved two days of absolute misery for me working through this circular dependency issue. Thank you 🙏 |
Follow up to confirm this worked for me as well. Additional thank you! |
If you use reactjs then
then import so
|
I keep running into circular dependency issues, which mostly seem to stem from inferring
RootState
from therootReducer
.What happens in many of my tests is that they import things from modules via
index.ts
files, which list a bunch of files. In many cases, this triggers the loading of files that depend onRootState
, which needsrootReducer
, which needs all the other reducers, all of which are loaded from modules viaindex.ts
files. At this point, often one of these index files is hit for the second time and the loader halts, leaving several variablesundefined
and resulting in cryptic error messages in the test output. If this doesn't go wrong, there is still a possibility for things to go wrong in the dependencies of these reducers.What is the recommended pattern here? Some approaches I can think of are:
RootState
inference and just define it explicitly.index.ts
. Do something similar with all of the reducer dependencies.I'm currently trying out something similar to the third option. Any thoughts?
The text was updated successfully, but these errors were encountered: