I'm doing some FE development for the first time in quite some time, and I'm puzzled by a TypeScript issue I'm getting when trying to use Redux in Typescript.
I'm following the instructions on the Redux Toolkit site (https://redux-toolkit.js.org/tutorials/typescript) to setup redux with Typescript.
With this simple code (almost identical to the example code in the docs):
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
import { fabric } from "fabric";
import { RootState } from "./store";
// Define a type for the slice state
type EditorState = {
canvas: fabric.Canvas | undefined;
};
// Define the initial state using that type
const initialState: EditorState = {
canvas: undefined,
};
export const editorSlice = createSlice({
name: "editor",
// `createSlice` will infer the state type from the `initialState` argument
initialState,
reducers: {
// Use the PayloadAction type to declare the contents of `action.payload`
setCanvas: (state, action: PayloadAction<fabric.Canvas>) => {
state.canvas = action.payload; // <--- state.canvas is where the error is
},
},
});
export const { setCanvas } = editorSlice.actions;
// Other code such as selectors can use the imported `RootState` type
export const getCanvas = (state: RootState) => state.editor.canvas;
export default editorSlice.reducer;
I get the following error under state.canvas
in the line state.canvas = action.payload;
:
Type 'Canvas' is not assignable to type 'WritableDraft<Canvas>'.
The types of '_activeObject.fill' are incompatible between these types.
Type 'string | Pattern | Gradient | undefined' is not assignable to type 'string | WritableDraft<Pattern> | WritableDraft<Gradient> | undefined'.
Type 'Pattern' is not assignable to type 'string | WritableDraft<Pattern> | WritableDraft<Gradient> | undefined'.
Type 'Pattern' is not assignable to type 'WritableDraft<Pattern>'.
Types of property 'source' are incompatible.
Type 'string | HTMLImageElement' is not assignable to type 'string | WritableDraft<HTMLImageElement>'.
Type 'HTMLImageElement' is not assignable to type 'string | WritableDraft<HTMLImageElement>'.
Type 'HTMLImageElement' is not assignable to type 'WritableDraft<HTMLImageElement>'.
Types of property 'offsetParent' are incompatible.
Type 'Element | null' is not assignable to type 'WritableDraft<Element> | null'.
Type 'Element' is not assignable to type 'WritableDraft<Element>'.
The types of 'ownerDocument.body.shadowRoot' are incompatible between these types.
Type 'ShadowRoot | null' is not assignable to type 'WritableDraft<ShadowRoot> | null'.
Type 'ShadowRoot' is not assignable to type 'WritableDraft<ShadowRoot>'.
Types of property 'adoptedStyleSheets' are incompatible.
Type 'CSSStyleSheet[]' is not assignable to type 'WritableDraft<CSSStyleSheet>[]'.
Type 'CSSStyleSheet' is not assignable to type 'WritableDraft<CSSStyleSheet>'.
Types of property 'ownerNode' are incompatible.
Type 'Element | ProcessingInstruction | null' is not assignable to type 'WritableDraft<Element> | WritableDraft<ProcessingInstruction> | null'.
Type 'Element' is not assignable to type 'WritableDraft<Element> | WritableDraft<ProcessingInstruction> | null'.
I can't work out what the problem is. If I change the canvas
key to be a string, everything works as expected.
Any help much appreciated...
CodePudding user response:
There's two problems here, one conceptual and one technical.
The conceptual problem is that a fabric.Canvas
is not "data", and thus doesn't belong in the Redux state. You should only put plain JS objects and arrays into Redux. That fabric.Canvas
is neither, and should be held in the UI layer.
The specific error is that something about Immer's TS typing explodes when you put a deeply nested / recursive object like a DOM node or similar into the Redux state. (But that's sort of a good thing in this case, because it's exploding when you're trying to do something you shouldn't do anyway :) )