我有许多 useReducers 和 useContext,其中出现了与下面列出的错误 (TS2554) 类似的错误。 我选择了 AuthReducer,因为它是最简单的。 对于每个 Action 调度,我都会收到相同的错误。我一直在寻找其他解决方案并尝试它们,添加了更多定义,但显然我没有做我应该做的事情!
这是我使用 Typescript 进行的第一个项目,所以放轻松!
据我所知,Dispatch 不期待任何参数,但正在接收参数。但是,当我声明我的 AuthReducer 时,它有一个 Actions 类型的 action 参数并返回 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;
答案 0 :(得分:0)
问题在于:
const AuthReducer = (
state: typeof initialState,
action: Actions
): AuthState ...
typescript 无法将您的类型 typeof initialState
和 AuthState
联系起来。但是 useReducer
的重载取决于 reducer
的类型来推断正确的结果类型。
这里有几个重构选项。你可以告诉打字稿那些是相同的类型:
const AuthReducer = (
state: AuthState,
action: Actions
): AuthState
或者让你的 initialState
更轻松一些:
const initialState: AuthState = {....}
问题的核心是类型TypeofA
和A
:
const a = { a: null }
type TypeofA = typeof a
type A = { a: string | null }
并不完全相同。将字段声明为 | string
时会丢失 null
。为了使它们相等,您可以编写带有类型断言的 a
对象:
const a = { a: null as string | null }
或者直接说明a
的类型:
const a: A = { a: null }