Typescript + Redux Toolkit, аргумент типа «T» не может быть назначен параметру типа «WritableDraft<T>»

Я новичок в Typescript и пытаюсь использовать Redux-Toolkit с ним в своем приложении React. Здесь я пытаюсь создать приложение To Do с вложенным состоянием, где каждый ToDo содержит массив Comment. Вот интерфейсы:

Comment.ts

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

ToDo.ts

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

Тогда в моем ToDoSlice:

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

Компилятор TS добавляет это в строку 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'.


Я попытался привести action.payload к типу WritableDraft<ToDo>, и ошибка исчезла.

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

Однако аналогичная проблема возникает, когда я пытаюсь добавить Comment в существующий 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);
    }
}

где выдает другую ошибку:

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.

и кастинг action.payload.comment as WritableDraft<Comment> не подойдет. Ошибка почти осталась прежней.



Версия зависимостей внутри 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"
  },

Я запускаю ваш код и не вижу ошибок машинописи. я проверил ваш код, используя реакцию v17.0.2 и redux-toolkit v1.5.1. Можете ли вы указать редукс-инструментарий и версию реакции? Я не уверен, но может машинописный текст выдает эту ошибку, когда вы пытаетесь отправить с неправильной полезной нагрузкой. Также здесь некорректно использовать тип WritableDraft. state внутри функции редуктора есть Draft.

Muhammad Nouman Rafique 14.11.2022 20:34

Спасибо за ответ, теперь я отредактировал сообщение, чтобы показать версии внутри package.json. Typescript сообщил об этой ошибке в строке state.push(action.payload), когда я еще не написал никакой логики диспетчеризации

AdmiJW 15.11.2022 01:21

После использования вашего package.json я все еще не вижу ошибок машинописного текста. Можете ли вы создать минимальный рабочий пример с помощью песочницы, такой как codeandbox.io, чтобы было легко определить проблему в вашем коде?

Muhammad Nouman Rafique 15.11.2022 13:05

Конечно. Вот коды и коробка: codeandbox.io/s/gifted-bouman-5q2qm2. Если вы откроете toDoSlice.ts в каталоге src/redux, вы увидите красную волнистую линию в строках 14 и 25. Как ни странно, приложение отлично работает в codeandbox, но не на моем локальном компьютере, я думаю, что codeandbox строго не проверяет Typescript, потому что, если Я меняю state.toDoList.push(action.payload); на что-то вроде state.toDoList.push(action.payload.notexist), приложение по-прежнему работает нормально (хотя с волнистыми линиями, указывающими на ошибку)

AdmiJW 15.11.2022 13:34
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
4
364
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

вы должны написать это:

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

Спасибо за ответ, к сожалению, это не снимает проблему. Он по-прежнему сообщает о той же ошибке, как если бы я написал state.push(action.payload)

AdmiJW 14.11.2022 13:59
Ответ принят как подходящий

В файле ToDo.ts внутри папки models вам просто нужно импортировать интерфейс Comment из Comment.ts.

import { Comment } from './Comment'

Это исправит эту ошибку машинописного текста.

Боже мой, большое спасибо. Не могу поверить, что вся проблема связана с коллизией типов Comment!

AdmiJW 15.11.2022 15:08

Другие вопросы по теме