Search code examples
reactjstypescriptfirebaseredux-thunkredux-toolkit

Getting headaches using Firebase 9, Redux Toolkit and Typescript in React. 'dispatch' somehow has type 'never'?


I'm trying to migrate an existing but old project to newer technologies, and specifically those mentioned in the title. I have little experience with Typescript, none with redux-toolkit and I'm used to Firebase v8 but migrating to v9 for modularity.

So, in my firebase realtime database I have a users table that I want to fetch some informations from, and I'm trying to achieve this through createAsyncThunk from @reduxjs/toolkit but with bad luck to this point. Standard actions are processed the way they're supposed to so it's definitely the thunk thing creating problems. I'm attaching some code:

The thunk

import { createAsyncThunk } from "@reduxjs/toolkit";
import { ref, onValue, DataSnapshot, child, DatabaseReference } from "firebase/database";
import { usersDb } from '../Firebase/utils';
import { MyBrandAppUser } from "../Types/MyBrandAppUser";

export const fetchMyBrandAppUser = createAsyncThunk('users/fetchMyBrandAppUser', async (uid: string, thunkAPI) => {
    const userEntry: DatabaseReference = child(usersDb, uid);
    let theUser: MyBrandAppUser | null = null;

    await onValue(userEntry, (snapshot: DataSnapshot) => {
        if( snapshot.exists() ) 
            theUser = <MyBrandAppUser>snapshot.val();
        else
            return null;
    }, 
    (err: Error) => {
        thunkAPI.rejectWithValue(err)
    });
    
    return theUser;  
})

I'm afraid this first part won't achieve what I assume it should since that onValue won't return a promise, but that's another topic for another time maybe.

The store

import { configureStore, EnhancedStore } from "@reduxjs/toolkit";
import userReducer from '../Features/Auth';
import logger from "redux-logger";
import thunk from "redux-thunk";
import { useDispatch } from 'react-redux'

export const store: EnhancedStore = configureStore({
    reducer: {
        auth: userReducer,
    },

    middleware: (getDefaultMiddleware) => getDefaultMiddleware({
        serializableCheck: false,
    }).concat(logger).concat(thunk)
})

export type AppDispatch = typeof store.dispatch;
export const useAppDispatch = () => useDispatch<AppDispatch>();

My users slice:

import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { User } from "firebase/auth";
import { WritableDraft } from "immer/dist/internal";
import { UserState } from "../../Types/Redux/States";
import { fetchMyBrandAppUser  } from "../../API/fetchUser";
import { MyBrandAppUser } from "../../Types/MyBrandAppUser";

const initialState: UserState = {
    firebaseUser: undefined,
    myBrandAppUser: undefined,
}

const authSlice = createSlice({
    name: "users",
    initialState,
    reducers: {
        setFirebaseUser: (state: WritableDraft<UserState>, action:PayloadAction<User | null>) => {
            state.firebaseUser = action.payload;
        }, 
    }, 

    extraReducers: builder => {
        builder.addCase(fetchMyBrandAppUser.fulfilled, (state: WritableDraft<UserState>, action) => {
            state.myBrandAppUser = action.payload;
        })
    }
})

export const { setFirebaseUser } = authSlice.actions;
export default authSlice.reducer;

But now if I try to call dispatch(fetchMyBrandAppUser(userID)) typescript won't let me, with the following complaint:

  1. For a regular action: Argument of type '{ payload: User | null; type: string; }' is not assignable to parameter of type 'never'.ts(2345)
  2. For thunk actions: Argument of type 'AsyncThunkAction<null, string, {}>' is not assignable to parameter of type 'never'.ts(2345)

What am I doing wrong?


Solution

  • I solved the issue by removing the EnhancedStore type on the store, for future reference.