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

TypeScript+Redux Toolkit报错:Canvas无法赋值给WritableDraft<Canvas>

问题分析

这个错误源于Redux Toolkit底层依赖的Immer库会将state包装为WritableDraft类型以实现不可变更新,而fabric.Canvas实例包含DOM相关的复杂对象(如HTMLImageElement、ShadowRoot等),Immer无法为这些浏览器原生DOM类型生成对应的WritableDraft包装类型,最终导致类型不兼容。

解决方案

方案1:让fabric.Canvas支持Immer的draft处理

手动给fabric.Canvas原型添加Immer的可标记属性,告知Immer可以正确处理该类型:

import { fabric } from "fabric";
import { immerable } from "immer";

// 扩展fabric.Canvas,使其支持Immer的draft操作
fabric.Canvas.prototype[immerable] = true;

添加这段代码后,Immer就能正确识别并处理fabric.Canvas实例,类型错误会自动消失。

方案2:类型断言(临时快速解决)

如果不想修改fabric的原型,可以直接在赋值时使用类型断言跳过类型检查:

setCanvas: (state, action: PayloadAction<fabric.Canvas>) => {
    state.canvas = action.payload as WritableDraft<fabric.Canvas>;
},

注意:这种方法只是绕过类型检查,并未从根本上解决Immer处理DOM对象的问题,不推荐在生产环境长期使用。

方案3:遵循Redux最佳实践,不存储DOM实例

Redux的store应当存储可序列化的状态数据,而非DOM实例或复杂第三方库实例。更合理的做法是:

  • 仅在组件中持有fabric.Canvas实例
  • 将画布的状态(比如所有图形的属性、位置、层级等)序列化为普通对象存储在Redux中
  • 当Redux状态变化时,在组件中同步更新canvas实例

这种方法既能避免类型问题,也符合Redux的设计原则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 13:35:20