Using Redux in combination with Firebase authentication

I'm currently working on implementing authentication in my React application using Redux with Redux Toolkit. Here's what I have so far: I've created a sign-in function utilizing createAsyncThunk

 export const signin = createAsyncThunk(
  'authentication/signin',
  async (signinCredentials: userData, { rejectWithValue }) => {
    const { email, password } = signinCredentials;
    await signInWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        // Signed in
        const user = userCredential.user;
        return user;
      })
      .catch((error) => {
        console.log(error.message);
        const errorMessage = error.message;
        return rejectWithValue(errorMessage);
      });
  }
);

I've defined an interface for userState as follows:

  export interface userState {
  user: object | null;
  status: 'idle' | 'loading' | 'failed';
  isAuth: boolean;
  message: string;
}

Here is the initial state:

 const initialState: userState = {
  user: null,
  status: 'idle',
  isAuth: false,
  message: '',
};

The issue lies within my auth slice component. Whenever I try to access action.payload, TypeScript throws errors at specific points that I've marked down.

export const authSlice = createSlice({
  name: 'authentication',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(signin.pending, (state) => {
        state.status = 'loading';
        state.isAuth = false;
      })
      .addCase(signin.fulfilled, (state, action) => {
        state.status = 'idle';
        state.isAuth = true;
        state.user = action.payload; // Type void is not assignable to type 'object' | null
      })
      .addCase(signin.rejected, (state, action) => {
        state.status = 'failed';
        state.isAuth = false;
        state.message = action.payload; // Type 'unknown' is not assignable to type 'string'
      })     
  },
});

I've been troubleshooting these issues for some time now and can't seem to pinpoint the exact problem. I've provided as much detail as possible, but if you require more information, please feel free to reach out. Thank you.

Answer №1

For more information, visit usage-with-typescript#createasyncthunk

To ensure correct inference of the action.payload type in case reducer, it is important to provide the correct types of generic arguments for createAsyncThunk, including type declarations for various fields such as:

type AsyncThunkConfig = {
  /** return type for `thunkApi.getState` */
  state?: unknown
  /** type for `thunkApi.dispatch` */
  dispatch?: Dispatch
  /** type of the `extra` argument for the thunk middleware, which will be passed in as `thunkApi.extra` */
  extra?: unknown
  /** type to be passed into `rejectWithValue`'s first argument that will end up on `rejectedAction.payload` */
  rejectValue?: unknown
  /** return type of the `serializeError` option callback */
  serializedErrorType?: unknown
  /** type to be returned from the `getPendingMeta` option callback & merged into `pendingAction.meta` */
  pendingMeta?: unknown
  /** type to be passed into the second argument of `fulfillWithValue` to finally be merged into `fulfilledAction.meta` */
  fulfilledMeta?: unknown
  /** type to be passed into the second argument of `rejectWithValue` to finally be merged into `rejectedAction.meta` */
  rejectedMeta?: unknown
}

By specifying these types correctly, like in the example below, you can ensure proper type inference:

Example:

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';

interface userData {
  email: string;
  password: string;
}

export const signin = createAsyncThunk<{ email: string }, userData, { rejectValue: string }>(
  'authentication/signin',
  async (signinCredentials: userData, { rejectWithValue }) => {
    const { email, password } = signinCredentials;
    try {
      throw new Error('password incorrect');
    } catch (error) {
      return rejectWithValue(error.message);
    }
  },
);

export interface userState {
  user: object | null;
  status: 'idle' | 'loading' | 'failed';
  isAuth: boolean;
  message: string;
}
const initialState: userState = {
  user: null,
  status: 'idle',
  isAuth: false,
  message: '',
};

export const authSlice = createSlice({
  name: 'authentication',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(signin.pending, (state) => {
        state.status = 'loading';
        state.isAuth = false;
      })
      .addCase(signin.fulfilled, (state, action) => {
        state.status = 'idle';
        state.isAuth = true;
        state.user = action.payload;
      })
      .addCase(signin.rejected, (state, action) => {
        state.status = 'failed';
        state.isAuth = false;
        if (action.payload) {
          state.message = action.payload;
        }
      });
  },
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issues with utilizing the react update addon to modify the redux state

Here is the state of my reducer as displayed by console.log: state:{getMessagesRequest: false,projects:[]} The projects array contains objects with the following structure: {messages:Array[0],userid:'foo',username:'bar'} In order to ...

Guide on sending a service instance to a React Router component using TypeScript

Consider the code snippet below: //routes.tsx const auth = new AuthService(); export default <Route component={ Layout }> <Route path='/login' components={{body:Login}} </Route>; //layout.tsx export interface LayoutProps { ...

How can I compel npm to resolve dependencies flatly?

I am working on a project where multiple frontends share a common library. The module dependencies for these projects are managed using npm. In the package.json file of each project, I specify: "dependencies": { "mylib": "file:../<...path...> ...

Retrieving a video file from the input and showcasing it using Typescript

Currently, I have implemented this code in order to retrieve an image that has been "uploaded" into the browser using the <input type="file"> tag, and then sending the data to a component that will utilize it. fileReady(e) { let file: File = e[ ...

When accessing the innerHTML and outerHTML properties on an HTMLElement, they may return undefined without triggering

Task: My goal is to take an HTML string, make changes to certain attributes of image tags within it, and then return the modified HTML string. The function I have developed follows these steps: private resolveImagesInHTML (body: string): string { le ...

The correct method to effectively type out a JSON object

Recently, I came across an article on that mentioned the possibility of importing JSON objects into a TypeScript project. Intrigued, I decided to give it a try by importing the following JSON: { "defaultLanguage": "en", "languageMap": { "en": "En ...

How can I initiate an Ajax request in a beforeAll function for Angular 2+ Protractor end-to-end tests?

I'm facing a challenge in Angular 6 e2e tests where I need to execute a POST request to my API within the beforeAll block. Despite trying various methods, I haven't been successful so far. Below is a description of my situation. To start, create ...

Error code 0x800a1391 - JavaScript runtime error: 'module' has not been defined

My background is in C++ and I am just beginning to explore TypeScript. I'm facing a runtime error while trying to implement a design (interface/class) that spans multiple files. The error message reads: 0x800a1391 - JavaScript runtime error: 'mod ...

Tips on obtaining the current date format (e.g. dd/mm/yyyy or mm/dd/yyyy) on the client side

I am currently working with the datepicker control, and I need to adjust the date format based on my browser's settings - either dd/mm/yyyy or mm/dd/yyyy. For example: if my browser date is 22/06/2019, then I should use "dd/MM/yyyy" format in the dat ...

Steps to turn off the creation of "exports.__esModule = true;" and "require('lib');"

Example: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA- ...

When using TypeScript, it may not always accurately infer props from React.ComponentType

I have developed a function that is designed to take a ComponentType and its respective props as input, enabling me to inject those props along with the RouteComponentProps. const routeComponentFactory = <TProps extends {}>( Component: React.Com ...

Collective picture in the exhibit

I recently created a photo gallery that showcases various images sorted by categories. In this setup, I have one object containing both images and their respective categories, and another object solely dedicated to storing the categories. The challenge I ...

Unraveling the mysteries of webpack configuration

import * as webpack from 'webpack'; ... transforms.webpackConfiguration = (config: webpack.Configuration) => { patchWebpackConfig(config, options); While reviewing code within an Angular project, I came across the snippet above. One part ...

In TypeScript, deduce the optional generic type automatically

Feeling a bit out of my depth here. I need to perform an inference on a generic that includes an optional "parse" function which returns the formatted value [or throws]. They say code speaks louder than words, so let's take a look at the example: exp ...

Leveraging Global Variables for Validation in Angular (Angular 10)

I am currently creating a form in Angular 10 which involves the use of validators. Specifically, I have been utilizing the Validators.min() method within my form... Instead of manually inputting the value '100' in the Validators.min('100&ap ...

Can you explain the functionality of `property IN array` in the TypeORM query builder?

I'm looking to filter a list of entity ids using query builder in an efficient way. Here's the code snippet I have: await this._productRepo .createQueryBuilder('Product') .where('Product.id IN (:...ids)', { ids: [1, 2, 3, 4] ...

Oops! NullInjectorError: R3InjectorError(AppModule)[Number -> Number -> Number]: It looks like we forgot to provide a Number provider

I'm feeling a bit confused by the current situation. The application was functioning smoothly until I returned to work on it and started encountering this error. Surprisingly, my Compiler isn't flagging any errors, and as far as I can tell, there ...

Unable to utilize my TypeScript library within JavaScript code

I've hit a roadblock with a seemingly straightforward task and could really use some fresh perspective. I'm currently developing a custom TypeScript library intended for use in both TypeScript and JavaScript projects within our organization. Th ...

Diverse function for checking environment variables using ternary operators

We decided to develop a utility function for asserting environment variables. Our project requires certain local environment variables that are not needed when the application is deployed. To simplify the assertions throughout different files, we wanted to ...

Having trouble with Nextjs API Integration - encountering error 404

I'm currently facing a major issue and I've hit a dead end. I've been spending days trying to connect my local nextjs 14 app to the CVENT API, but I keep receiving a persistent 404 error. Here's what is displayed in the frontend console ...