I have a number of useReducers and useContext where I am getting similar errors as the one listed below (TS2554). I have picked out the AuthReducer as it is the simplest. I get the same error for each Action dispatch. I've toyed around looking at other solutions and trying them out, Added some more definitions but clearly I'm not doing what I'm supposed to be!
Its my first project that I'm working on with Typescript so go easy on me!
as far as I can tell Dispatch is not expecting any arguments but is receiving one. However when I declare my AuthReducer it has an action argument of type Actions and returns AuthState.
/AuthState.tsx:40:16 - error TS2554: Expected 0 arguments, but got 1.
40 dispatch({
41 type: USER_LOADED,
42 payload: res.data,
43 });
AuthReducer.tsx
import {
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT,
CLEAR_ERRORS,
} from '../types';
import { initialState } from './AuthState';
type Actions =
| {
type: 'USER_LOADED';
payload: {
name: string;
id: string;
};
}
| {
type: 'AUTH_ERROR';
payload?: string;
}
| {
type: 'LOGIN_SUCCESS';
payload: { token: string };
}
| {
type: 'LOGIN_FAIL';
payload: string;
}
| {
type: 'LOGOUT';
payload?: string;
}
| {
type: 'CLEAR_ERRORS';
};
interface AuthState {
token?: string | null;
isAuthenticated?: boolean;
loading: boolean;
user?: {
name: string;
id: string;
} | null;
error?: string | undefined | null;
}
const AuthReducer = (
state: typeof initialState,
action: Actions
): AuthState => {
switch (action.type) {
case USER_LOADED:
return {
...state,
isAuthenticated: true,
loading: false,
user: action.payload,
};
case LOGIN_SUCCESS:
localStorage.setItem('token', action.payload.token);
return {
...state,
...action.payload,
isAuthenticated: true,
loading: false,
};
case AUTH_ERROR:
case LOGIN_FAIL:
case LOGOUT:
localStorage.removeItem('token');
return {
...state,
token: null,
isAuthenticated: false,
loading: false,
user: null,
error: action.payload,
};
case CLEAR_ERRORS:
return {
...state,
error: null,
};
default:
return state;
}
};
export default AuthReducer;
AuthContext.tsx
import { createContext } from 'react';
import { initialState } from './AuthState';
type authContextType = {
loadUser: () => Promise<void> | null;
login: (formData: {
email: string;
password: string;
}) => Promise<void> | null;
logout: () => void;
clearErrors: () => void;
error: string | null;
isAuthenticated: boolean;
loading: boolean;
user: {
name: string;
id: string;
};
token: string;
};
const authContext = createContext<authContextType>(initialState); //TODO A more robust type is possible
export default authContext;
AuthState.tsx
import React, { useReducer } from 'react';
import axios from 'axios';
import AuthContext from './AuthContext';
import AuthReducer from './AuthReducer';
import setAuthToken from '../../utils/setAuthToken';
import {
USER_LOADED,
AUTH_ERROR,
LOGIN_SUCCESS,
LOGIN_FAIL,
LOGOUT,
CLEAR_ERRORS,
} from '../types';
export const initialState = {
loadUser: null,
login: null,
logout: () => {},
clearErrors: () => {},
token: localStorage.getItem('token'),
isAuthenticated: null,
loading: true,
error: null,
user: null,
};
const AuthState: React.FC = ({ children }) => {
const [state, dispatch] = useReducer(AuthReducer, initialState);
//Load User
const loadUser = async () => {
if (localStorage.token) {
setAuthToken(localStorage.token);
}
try {
const res = await axios.get('api/auth');
dispatch({
type: USER_LOADED,
payload: res.data,
});
} catch (err) {
dispatch({ type: AUTH_ERROR });
}
};
//Login User
const login = async (formData: { email: string; password: string }) => {
const config = {
headers: {
'Content-Type': 'application/json',
},
};
try {
const res = await axios.post('/api/auth', formData, config);
dispatch({
type: LOGIN_SUCCESS,
payload: res.data,
});
loadUser();
} catch (err) {
dispatch({
type: LOGIN_FAIL,
payload: err.response.data.msg,
});
}
};
//Logout
const logout = () => {
dispatch({ type: LOGOUT });
};
//Clear Errors
const clearErrors = () => {
dispatch({ type: CLEAR_ERRORS });
};
return (
<AuthContext.Provider
value={{
token: state.token,
isAuthenticated: state.isAuthenticated,
loading: state.loading,
user: state.user,
error: state.error,
loadUser,
login,
logout,
clearErrors,
}}
>
{children}
</AuthContext.Provider>
);
};
export default AuthState;