-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
'RootState' circularly references itself #2770
Comments
The main fallback option for this sort of issue is to infer the const rootReducer = combineReducers({
a: sliceA.reducer
})
type RootState = ReturnType<typeof rootReducer>; Does that help? |
@markerikson Unfortunately no, it doesn't. |
One of your slices references So export default slice.reducer becomes export default (slice.reducer as Reducer<typeof initialState>) |
@phryneas |
Well, it is one of your slices that causes it - you might have gone with the wrong one here. Comment them out until the message disappears, then you know which one to do this on. All I can say is that that reducer somewhere references |
@phryneas Slice at row 6 is fine. |
Do |
Well, there you have your circular type reference. Honestly, I can't do much with screenshots. If you give me a TypeScript playground that is complete enough to replicate your problem I can take a quick look and give a recommendation on how to solve it in your case. |
@phryneas, actually I left link to playground at the topic-starting message (here is duplicate) If passing state to generic type of async thunk makes circular reference, why do we need it at all? From another side, how we will know about type returned by |
I'll take a look later, missed that part. Thanks. Generally: something like this is usually not a problem if you just write normal logic. But if you add wrapping logic like you are doing here, it gets problematic. That's just TS being TS. (without the |
So, after taking a look, you can interrupt that circle by doing something like const image1Slice = createImageSlice("image1", fetchImage1) as Reducer<ImageState, AnyAction>;
const image2Slice = createImageSlice("image2", fetchImage2) as Reducer<ImageState, AnyAction>; The problem is really that the Generally, if I may ask:
|
Honestly, I do not know. This is a TypeScript quirk - we cannot do a lot about it. And yes, changing your factory function in some way could also do that, but as you noticed it's not the best idea either. In the next TS version, it will be possible to do const image1Slice = createImageSlice("image1", fetchImage1) satisfies Reducer<ImageState, AnyAction> as Reducer<ImageState, AnyAction>;
const image2Slice = createImageSlice("image2", fetchImage2) satisfies Reducer<ImageState, AnyAction> as Reducer<ImageState, AnyAction>; which is also not more beautiful but will at least be typesafe despite being a cast. |
Yeah. Another question - why do you not expose |
You really should not have a code of conduct that disallows the
Because you can just as well extend from an empty object - that base object has no value or meaning. You will be thrilled about #2604 though - it is available in our 1.9 alphas. |
@tsarapke You can resolve the problem by this workaround. Enjoy it. import { AsyncThunk, AsyncThunkPayloadCreator, Dispatch } from '@reduxjs/toolkit';
import { RootState } from './store';
declare module '@reduxjs/toolkit' {
// https://stackoverflow.com/questions/64793504/cannot-set-getstate-type-to-rootstate-in-createasyncthunk
type AsyncThunkConfig = {
state?: unknown;
dispatch?: Dispatch;
extra?: unknown;
rejectValue?: unknown;
serializedErrorType?: unknown;
};
function createAsyncThunk<
Returned,
ThunkArg = void,
ThunkApiConfig extends AsyncThunkConfig = {
state: RootState;
},
>(
typePrefix: string,
payloadCreator: AsyncThunkPayloadCreator<
Returned,
ThunkArg,
ThunkApiConfig
>,
options?: any
): AsyncThunk<Returned, ThunkArg, ThunkApiConfig>;
} |
@Emiya0306 Many thanks! I would prefer yours one. Looks more reasonable than continuous type-casting. Love it. Probably one note. Maybe it would be better to describe
|
@tsarapke Hi, I just try to make same implementation , but any way I have getState: () => unknown. What I made wrong ? |
@EgorKlimenchuk it doesn't work for 1.9+. Only for 1.8.6 or below |
@tsarapke aaa okey, but before update I was on 1.8.5 |
@EgorKlimenchuk if you are using 1.8.6 or below, it depends on env. But you should check if your typescript takes into account your |
@tsarapke Yes if I declare the type in custom.d.ts , I can see difference. For example I can directly change AsyncThunkConfig . But anyway getState return unknown |
|
@phryneas Can I wrap createAsyncThunk or do I have to use withTypes every time? |
@phryneas when I use createAsyncThunk.withTypes and import RootState into slice I have this circular error |
You do that once per project. This is not about importing it into the same file, it is because you create an actual type circle of calls. Usually, that happens because you are omitting the |
@phryneas I found one solution in tsconfig.json add "declaration": false. But honestly I don't want to do it, cause I might create another problem |
@phryneas
I have tried to split into different files RootState and setupStore, but it was the same problem |
Comment out all of your reducers. Please don't give incomplete screenshots - nobody can help you with that. |
Hello there!
We are migrating our applications to use
@reduxjs/toolkit
and faced with issue ofRootState
circularly references itself, andstore
implicitly has typeany
when we are trying to specify state type ofcreateAsyncThunk<Blob, { height: number, width: number }, { state: RootState }>
.Reproduction
Screenshot:
We've already read some of existing topics here, like:
#2462
#2237
#1126
#324
But don't found any solution to handle it.
In addition, it would be nice to have exposing of
AsyncThunkConfig
from@reduxjs/toolkit
, as for now there is no way infer that type in slice/reducer custom factory (only by specifyingany
)The text was updated successfully, but these errors were encountered: