Redux Toolkit中原始值与对象初始状态的类型差异问题
Redux Toolkit原始值状态更新类型错误原因解析
问题场景
使用Redux Toolkit时尝试两种初始状态设置方式:
- 方式一:直接赋值原始值
null,类型声明为number | null,更新状态时出现类型错误 - 方式二:赋值包含
test属性的对象,属性类型为number | null,更新状态无错误
带错误的实现
import { createSlice, PayloadAction } from "@reduxjs/toolkit"; type InitialState = number | null; const initialState: InitialState = null; const SelectedTestSlice = createSlice({ name: "Test", initialState, reducers: { selectTest: (state, action: PayloadAction<number>) => { state = action.payload; // <-- Type 'number' is not assignable to type 'null' }, }, }); export const { selectTest } = SelectedTestSlice.actions; export default SelectedTestSlice.reducer;
无错误的实现
import { createSlice, PayloadAction } from "@reduxjs/toolkit"; type InitialState = { test: number | null; }; const initialState: InitialState = { test: null, }; const SelectedTestSlice = createSlice({ name: "Test", initialState, reducers: { selectTest: (state, action: PayloadAction<number>) => { state.test = action.payload; // <-- No error }, }, }); export const { selectTest } = SelectedTestSlice.actions; export default SelectedTestSlice.reducer;
原因解析
1. TypeScript类型推断差异
- 当直接将
initialState设为原始值null时,TypeScript会优先推断state的类型为字面量类型null,而非你声明的number | null联合类型。此时给state赋值number类型的payload,自然触发类型不兼容错误。 - 当使用对象作为初始状态时,TypeScript会结合你声明的
InitialState类型,推断出state.test的类型是number | null联合类型,给该属性赋值number完全符合类型要求。
2. Immer对原始值与引用值的处理不同
Redux Toolkit内置的Immer库负责处理状态不可变性:
- 对于原始值(number、string、null等),Immer无法代理修改它们(原始值是值类型,无属性可修改),必须通过返回新值的方式更新状态,而非直接给
state赋值。 - 对于引用值(对象、数组等),Immer会创建代理对象,允许直接修改属性,内部自动转换为不可变的状态更新。
修复原始值场景的错误
要让原始值场景正常工作,需同时解决类型推断和Immer使用问题:
import { createSlice, PayloadAction } from "@reduxjs/toolkit"; type InitialState = number | null; const initialState: InitialState = null; // 显式指定createSlice泛型参数,确保state类型为联合类型 const SelectedTestSlice = createSlice<InitialState, { selectTest: PayloadAction<number>; }>({ name: "Test", initialState, reducers: { selectTest: (state, action) => { // 原始值必须返回新状态,不能直接赋值state= return action.payload; }, }, }); export const { selectTest } = SelectedTestSlice.actions; export default SelectedTestSlice.reducer;
内容的提问来源于stack exchange,提问作者Dev
相关产品推荐
相关产品推荐

