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
相关产品推荐
相关产品推荐

