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

TypeScript+Redux Toolkit中WritableDraft类型不兼容问题求助

问题:Redux Toolkit中WritableDraft与自定义类型不兼容错误

问题背景

在React+TypeScript项目中使用Redux Toolkit开发待办应用,定义了包含Comment数组的嵌套ToDo状态,但在编写slice的reducer时出现类型不兼容错误:

  • 添加ToDo时,state.push(action.payload)抛出ToDo无法赋值给WritableDraft<ToDo>的错误
  • 给现有ToDo添加Comment时,toDo.comments.push(action.payload.comment)抛出Comment无法赋值给WritableDraft<Comment>的错误,且强制类型转换无法解决

自定义类型定义

Comment.ts

export interface Comment {
    id: number;
    comment: string;
}

ToDo.ts

export interface ToDo {
    id: number;
    title: string;
    description: string;
    comments: Array<Comment>;
}

Slice代码及错误

初始Slice代码:

export const toDoSlice = createSlice({
    name: 'toDoSlice',
    initialState: [] as Array<ToDo>,
    reducers: {
        addToDo: (state, action: PayloadAction<ToDo> ) => {
            state.push(action.payload);
        },
        addComment: (state, action: PayloadAction<{toDoId: number, comment: Comment}>) => {
            const toDo = state.find(toDo => toDo.id === action.payload.toDoId);
            if (toDo) {
                toDo.comments.push(action.payload.comment);
            }
        }
    }
});

核心报错信息:

Argument of type 'Comment' is not assignable to parameter of type 'WritableDraft<Comment>'.
  Type 'Comment' is missing the following properties from type 'WritableDraft<Comment>': data, length, ownerDocument, appendData, and 59 more.

项目依赖版本:

"dependencies": {
    "@reduxjs/toolkit": "^1.9.0",
    "@testing-library/jest-dom": "^5.14.1",
    "@testing-library/react": "^13.0.0",
    "@testing-library/user-event": "^13.2.1",
    "@types/jest": "^27.0.1",
    "@types/node": "^16.7.13",
    "@types/react": "^18.0.0",
    "@types/react-dom": "^18.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-redux": "^8.0.5",
    "react-router-dom": "^6.4.3",
    "react-scripts": "5.0.1",
    "typescript": "^4.4.2",
    "web-vitals": "^2.1.0"
  },

解决方案

1. 解决类型命名冲突(核心原因)

错误根源是自定义的Comment接口与浏览器DOM原生的Comment类型(代表DOM注释节点)重名,导致TypeScript混淆了两个类型,进而在Immer(Redux Toolkit内置的不可变更新库)处理状态时,错误地将自定义类型与DOM类型进行匹配。

解决步骤:

  • 重命名自定义的Comment接口,避免与DOM类型冲突
  • 更新所有引用该类型的代码

修改后的Comment.ts:

export interface TodoComment {
    id: number;
    comment: string;
}

修改后的ToDo.ts:

import { TodoComment } from './Comment';

export interface ToDo {
    id: number;
    title: string;
    description: string;
    comments: Array<TodoComment>;
}

修改后的Slice代码:

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { ToDo, TodoComment } from './types'; // 根据实际路径调整

export const toDoSlice = createSlice({
    name: 'toDoSlice',
    initialState: [] as ToDo[],
    reducers: {
        addToDo: (state, action: PayloadAction<ToDo>) => {
            state.push(action.payload);
        },
        addComment: (state, action: PayloadAction<{toDoId: number, comment: TodoComment}>) => {
            const toDo = state.find(todo => todo.id === action.payload.toDoId);
            if (toDo) {
                toDo.comments.push(action.payload.comment);
            }
        }
    }
});

2. 可选:升级TypeScript版本

当前使用的TypeScript 4.4.2版本较旧,与Redux Toolkit 1.9.0的兼容性虽无问题,但升级到4.9及以上版本可以获得更好的类型推断能力,减少类似的类型混淆问题。

3. 避免强制类型转换

之前使用的as WritableDraft<ToDo>强制转换只是临时掩盖问题,并未解决根本冲突,建议移除这类转换,通过正确的类型定义解决问题。

内容的提问来源于stack exchange,提问作者AdmiJW

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 12:20:53