Jin Park
Jin Park

Reputation: 461

I got Type-errors while converting my Slice.js file to ts (redux tool kit)

I just created my sample Redux tool kit with js files. now I am trying to convert them to typescript. some of the error is now fixed. but I have no idea how to fix the two errors below.

  1. Property 'name' does not exist on type 'void'. <<<< also for email, password... and token
  2. A computed property name must be of type 'string', 'number', 'symbol', or 'any' <<<< for signupUser.fulfilled, signupUser.pending... so on

Please refer to my comments within the code below and please help me to how to solve the problems

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


export interface UserState {
  username: string;
  email: string;
  isFetching: boolean;
  isSuccess: boolean;
  isError: boolean;
  errorMessage: string;
}

interface check {
  name: string;
  email: string;
  password: string;
}

const initialState: UserState = {
  username: "",
  email: "",
  isFetching: false,
  isSuccess: false,
  isError: false,
  errorMessage: "",
}



export const signupUser = createAsyncThunk(
  'users/signupUser',
// 
// 
// async ({ name, email, password} ... <<<  This is the problem 1. 
//

  async ({ name, email, password }, thunkAPI) => {
    try {
      const response = await fetch(
        'https://mock-user-auth-server.herokuapp.com/api/v1/users',
        {
          method: 'POST',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            name,
            email,
            password,
          }),
        },
      );
      const data = await response.json();
      console.log('data', data);

      if (response.status === 200) {
        localStorage.setItem('token', data.token);
        return { ...data, username: name, email };
      }
      return thunkAPI.rejectWithValue(data);
    } catch (e) {
      console.log('Error', e.response.data);
      return thunkAPI.rejectWithValue(e.response.data);
    }
  },
);

export const loginUser = createAsyncThunk(
  'users/login',
  async ({ email, password }, thunkAPI) => {
    try {
      const response = await fetch(
        'https://mock-user-auth-server.herokuapp.com/api/v1/auth',
        {
          method: 'POST',
          headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            email,
            password,
          }),
        },
      );
      const data = await response.json();
      console.log('response', data);
      if (response.status === 200) {
        localStorage.setItem('token', data.token);
        return data;
      }
      return thunkAPI.rejectWithValue(data);
    } catch (e) {
      console.log('Error', e.response.data);
      thunkAPI.rejectWithValue(e.response.data);
    }
  },
);

export const fetchUserBytoken = createAsyncThunk(
  'users/fetchUserByToken',
  async ({ token }, thunkAPI) => {
    try {
     const response = await fetch(
        'https://mock-user-auth-server.herokuapp.com/api/v1/users',
        {
          method: 'GET',
          headers: {
            Accept: 'application/json',
            Authorization: token,
            'Content-Type': 'application/json',
          },
        },
      ); 
      /* test case for Axios
      const response = await axios.get(
        'https://mock-user-auth-server.herokuapp.com/api/v1/users',
        {
          headers: {
            Accept: 'application/json',
            Authorization: token,
            'Content-Type': 'application/json',
          },
        },
      );
        */
      const data = await response.json();
      console.log('data', data, response.status);

      if (response.status === 200) {
        return { ...data };
      }
      return thunkAPI.rejectWithValue(data);
    } catch (e) {
      console.log('Error', e.response.data);
      return thunkAPI.rejectWithValue(e.response.data);
    }
  },
);

export const userSlice = createSlice({
  name: 'user',
  initialState: {
    username: '',
    email: '',
    isFetching: false,
    isSuccess: false,
    isError: false,
    errorMessage: '',
  },
  reducers: {
    clearState: state => {
      state.isError = false;
      state.isSuccess = false;
      state.isFetching = false;

      return state;
    },
  },
////
//// [signupUser.fulfilled] ... <<<< this is the problem 2.
////
////
  extraReducers: {
    [signupUser.fulfilled]: (state, { payload }) => {
      console.log('payload', payload);
      state.isFetching = false;
      state.isSuccess = true;
      state.email = payload.user.email;
      state.username = payload.user.name;
    },
    [signupUser.pending]: state => {
      state.isFetching = true;
    },
    [signupUser.rejected]: (state, { payload }) => {
      state.isFetching = false;
      state.isError = true;
      state.errorMessage = payload.message;
    },
    [loginUser.fulfilled]: (state, { payload }) => {
      state.email = payload.email;
      state.username = payload.name;
      state.isFetching = false;
      state.isSuccess = true;
      return state;
    },
    [loginUser.rejected]: (state, { payload }) => {
      console.log('payload', payload);
      state.isFetching = false;
      state.isError = true;
      state.errorMessage = payload.message;
    },
    [loginUser.pending]: state => {
      state.isFetching = true;
    },
    [fetchUserBytoken.pending]: state => {
      state.isFetching = true;
    },
    [fetchUserBytoken.fulfilled]: (state, { payload }) => {
      state.isFetching = false;
      state.isSuccess = true;

      state.email = payload.email;
      state.username = payload.name;
    },
    [fetchUserBytoken.rejected]: state => {
      console.log('fetchUserBytoken');
      state.isFetching = false;
      state.isError = true;
    },
  },
});

export const { clearState } = userSlice.actions;

export const userSelector = (state: { user: UserState}) => state.user;

Upvotes: 1

Views: 245

Answers (1)

phry
phry

Reputation: 44136

You'll need to define a type for the argument you put in there. If you only want to type the first argument and are fine with the defaults for thunkAPI, you can use

export const signupUser = createAsyncThunk(
  'users/signupUser',
  async ({ name, email, password }: ArgumentType, thunkAPI) => {

Otherwise, you'll have to declare generic arguments as described in https://redux-toolkit.js.org/usage/usage-with-typescript#createasyncthunk

const fetchUserById = createAsyncThunk<
  // Return type of the payload creator
  MyData,
  // First argument to the payload creator
  number,
  {
    dispatch: AppDispatch
    state: State
    extra: {
      jwt: string
    }
  }
>('users/fetchById', async (userId, thunkApi) => {

For problem #2 please see that we discourage the object map notation for extraReducers as it is less typesafe in general and does not work in TypeScript. Please use the builder notation as described in https://redux-toolkit.js.org/api/createSlice#the-extrareducers-builder-callback-notation

Upvotes: 1

Related Questions