You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:37:20