AdmiJW
AdmiJW

Reputation: 93

Typescript + Redux Toolkit, Argument of type 'T' is not assignable to parameter of type 'WritableDraft<T>'

I am new to Typescript and trying to use Redux-Toolkit with it in my React application. Here I am trying to create a To Do application with a nested state where each ToDo contains a array of Comment. Here are the interfaces:

Comment.ts

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

ToDo.ts

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

Then in my ToDoSlice:

export const toDoSlice = createSlice({
    name: 'toDoSlice',
    initialState: [] as Array<ToDo>,
    reducers: {
        addToDo: (state, action: PayloadAction<ToDo> ) => {
            state.push(action.payload);
        },
    }
});

The TS compiler throws this on the line state.push(action.payload):

TS2345: Argument of type 'ToDo' is not assignable to parameter of type 'WritableDraft<ToDo>'.
  Types of property 'comments' are incompatible.
    Type 'Comment[]' is not assignable to type 'WritableDraft<Comment>[]'.
      Type 'Comment' is not assignable to type 'WritableDraft<Comment>'.
        The types of 'ownerDocument.all' are incompatible between these types.
          Type 'HTMLAllCollection' is not assignable to type 'WritableDraft<HTMLAllCollection>'.
            'number' index signatures are incompatible.
              Type 'Element' is not assignable to type 'WritableDraft<Element>'.
                Types of property 'attributes' are incompatible.
                  Type 'NamedNodeMap' is not assignable to type 'WritableDraft<NamedNodeMap>'.
                    'number' index signatures are incompatible.
                      Type 'Attr' is not assignable to type 'WritableDraft<Attr>'.
                        Types of property 'childNodes' are incompatible.
                          Type 'NodeListOf<ChildNode>' is not assignable to type 'WritableDraft<NodeListOf<ChildNode>>'.
                            'number' index signatures are incompatible.
                              Type 'ChildNode' is not assignable to type 'WritableDraft<ChildNode>'.
                                Types of property 'parentElement' are incompatible.
                                  Type 'HTMLElement | null' is not assignable to type 'WritableDraft<HTMLElement> | null'.
                                    Type 'HTMLElement' is not assignable to type 'WritableDraft<HTMLElement>'.
                                      Types of property 'shadowRoot' are incompatible.
                                        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 'ProcessingInstruction' is not assignable to type 'WritableDraft<Element> | WritableDraft<ProcessingInstruction> | null'.


I tried to cast the action.payload to type WritableDraft<ToDo>, and the error does go away.

addToDo: (state, action: PayloadAction<ToDo> ) => 
    {state.push(action.payload as WritableDraft<ToDo>);
},

However, similar problem arises when I try to add a Comment into an existing ToDo:

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);
    }
}

where it gives another error:

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.

and casting action.payload.comment as WritableDraft<Comment> won't do. The error almost remains the same.



The version of the dependencies inside of the package.json:

"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"
  },

Upvotes: 2

Views: 4673

Answers (2)

Muhammad Nouman Rafique
Muhammad Nouman Rafique

Reputation: 1566

In ToDo.ts file inside models folder, you just need to import Comment interface from Comment.ts.

import { Comment } from './Comment'

This will fix that typescript error.

Upvotes: 2

paria
paria

Reputation: 31

you should write this:

reducers: {
    addToDo: (state, action: PayloadAction<ToDo> ) => {
        state.push(action.payload as ToDo);
    },

Upvotes: 1

Related Questions