我正在尝试使用React和Typescript设置我的第一个项目,但是我在rootReducer中遇到了这个错误:
Type 'Reducer<CombinedState<{ auth: never; error: never; }>, IRegisterUserAction | IAuthenticateUserAction | LogoutAction | ConfirmAccountAction | ISetErrorAction | IHideErrorAction>' is not assignable to type 'Reducer<{ auth: IAuthState; error: IErrorState; }, AnyAction>'.
参数“状态”和“状态”的类型不兼容。 输入'{auth:IAuthState;错误:IErrorState; } | undefined'不能分配给'CombinedState <{auth:never;错误:从不; }> |未定义”。 输入'{auth:IAuthState;错误:IErrorState; }'不能分配给'CombinedState <{auth:never;错误:从不; }>'。 输入'{auth:IAuthState;错误:IErrorState; }'不能分配给类型'{auth:never;错误:从不; }'。ts(2322)
我的rootReducer.ts:
const persistConfig = {
key: 'root',
storage,};
export const appReducers: Reducer<{ auth: IAuthState; error: IErrorState }> = combineReducers({
auth: authReducer,
error: errorReducer,});
export type RootState = ReturnType<typeof appReducers>;
const rootReducer = (state: CombinedState<RootState> | undefined, action: AuthActionTypes) => {
if (action.type === LOGOUT) {
state = undefined;
localStorage.clear();
}
return appReducers(state, action);};
export const persistedReducer = persistReducer(persistConfig, rootReducer);
我的authReducer.ts:
export const initialState = {
loggedIn: false,
username: null,
email: null,
role: null,
profileImage: null,};
const authReducer: Reducer<IAuthState, AuthActionTypes> = (state = initialState, action): IAuthState => {
switch (action.type) {
case AUTHENTICATE_USER: {
return {
...state,
loggedIn: true,
username: action.payload.username || null,
email: action.payload.email || null,
role: action.payload.role || null,
profileImage: action.payload.profileImage || null,
};
}
default:
return state;
}};
export default authReducer;
我的errorReducer.ts:
export const initialState = {
error: null,
validationErrors: {
username: null,
email: null,
password: null,
},
};
const errorReducer: Reducer<IErrorState, ErrorActionTypes> = (state = initialState, action): IErrorState => {
switch (action.type) {
case SET_ERROR: {
return {
...state,
error: action.payload.error || null,
validationErrors: {
username: action.payload.validationErrors.username || null,
email: action.payload.validationErrors.email || null,
password: action.payload.validationErrors.password || null
}
};
}
default:
return state;
}};
export default errorReducer;
我的store.ts:
export type AppState = {
auth: IAuthState;
error: IErrorState;
};
const initialState: AppState = {
auth: authInitialState,
error: errorInitialState
};
const middlewares = [thunk];
const configureStore = () => {
const store = createStore(persistedReducer, initialState,
composeWithDevTools(applyMiddleware(...middlewares)));
return store;
}
const store = configureStore();
const persistor = persistStore(store);
export { store, persistor };
我的authTypes.ts:
export const REGISTER_USER = 'REGISTER_USER';
export const AUTHENTICATE_USER = 'AUTHENTICATE_USER';
export const CONFIRM_ACCOUNT = 'CONFIRM_ACCOUNT';
export const LOGOUT = 'LOGOUT';
export type UserRegisterState = {
username: string;
email: string;
password: string;
passwordConfirm: string;
};
export type UserLoginState = {
username: string;
password: string;
};
export interface IRegisterUserAction extends Action<typeof REGISTER_USER> {
type: typeof REGISTER_USER;
}
export interface IAuthenticateUserAction extends Action<typeof AUTHENTICATE_USER> {
type: typeof AUTHENTICATE_USER;
payload: IAuthState;
}
export interface LogoutAction extends Action<typeof LOGOUT> {
type: typeof LOGOUT;
}
export interface ConfirmAccountAction extends Action<typeof CONFIRM_ACCOUNT> {
type: typeof CONFIRM_ACCOUNT;
}
export type AuthActionTypes = IAuthenticateUserAction | LogoutAction | ConfirmAccountAction
| IRegisterUserAction;
我的errorTypes.ts:
export const SET_ERROR = 'SET_ERROR';
export const HIDE_ERROR = 'HIDE_ERROR';
export interface ISetErrorAction extends Action<typeof SET_ERROR> {
type: typeof SET_ERROR;
payload: IErrorState;
}
export interface IHideErrorAction extends Action<typeof HIDE_ERROR> {
type: typeof HIDE_ERROR;
}
export type ErrorActionTypes = ISetErrorAction | IHideErrorAction;
我的authActions.ts:
export const registerUser: ActionCreator<ThunkAction<
Promise<void>,
RootState,
UserRegisterState,
IRegisterUserAction
>> = (userData: UserRegisterState) => async (dispatch: Dispatch) => {
try {
await signUpUser(userData);
} catch (error) {
dispatch({
type: SET_ERROR,
payload: {
error: error.response.data.message,
validationErrors: error.response.data.validationErrors,
},
});
}
};
export const authenticateUser: ActionCreator<ThunkAction<
Promise<void>,
RootState,
UserRegisterState,
IAuthenticateUserAction
>> = (userData: UserLoginState) => async (dispatch: Dispatch) => {
try {
const user = await signInUser(userData);
dispatch({
type: AUTHENTICATE_USER,
payload: user.data,
});
} catch (error) {
dispatch({
type: SET_ERROR,
payload: {
error: error.response.data.message,
validationErrors: error.response.data.validationErrors,
},
});
}
};
export const forgotUserPassword: ActionCreator<ThunkAction<
Promise<void>,
RootState,
{ userEmail: string },
IAuthenticateUserAction
>> = (userEmail: string) => async (dispatch: Dispatch) => {
try {
await forgotPassword(userEmail);
} catch (error) {
dispatch({
type: SET_ERROR,
payload: {
error: error.response.data.message,
validationErrors: error.response.data.validationErrors,
},
});
}
};
答案 0 :(得分:0)
const rootReducer = (state, action) => {
if (action.type === LOGOUT) {
state = undefined;
localStorage.clear();
}
return appReducers(state, action);
};
在此函数的“注销”分支中,您将状态设置为undefined
,这是不应该执行的,因为状态绝不能直接变异。减速器应返回状态的新副本。
起初我以为你在这里什么也没回来。现在,我知道您正在将状态设置为undefined
,以便可以恢复到初始状态。可以用appReducers
调用undefined
,但是您不能为此改变状态。尝试这样的事情:
const rootReducer: RootReducer = (state, action) => {
if (action.type === LOGOUT) {
localStorage.clear();
return appReducers(undefined, action);
}
return appReducers(state, action);
};
您在type AppState
中的store.ts
和type RootState
中的rootReducer.ts
都有相同的定义。因为值匹配,所以从技术上讲现在这不是问题,但是您希望将一个规范的定义放在一个位置。该位置应为rootReducer.ts
文件,因为避免循环导入是一种很好的做法,因此,当商店已经从reducer导入时,我们不希望将reducer从商店中导入。
您的rootReducer
在需要包含错误操作的情况下,将操作键入为AuthActionTypes
。这可能是错误的来源,但是当前的错误是关于状态而不是操作。
您的类型应如下所示:
export interface RootState {
auth: IAuthState;
error: IErrorState;
};
export type RootAction = AuthActionTypes | ErrorActionTypes;
export type RootReducer = Reducer<RootState, RootAction>
export const appReducers: RootReducer = ....
const rootReducer: RootReducer = (state, action) => {...};
使用reducer函数,您可以在函数本身中添加RootReducer
类型,也可以在参数和返回值中添加类型,但是不必同时执行。
注意:当我将鼠标悬停在类型为state
的函数上的RootReducer
上时,我看到state: RootState
却没有提到它可能是undefined
。我不知道为什么这是因为Reducer
的定义很清楚,状态可以是指定的类型,也可以是undefined
(type Reducer<S = any, A extends Action<any> = AnyAction> = (state: S | undefined, action: A) => S
)