cdmt
cdmt

Reputation: 923

React, Typescript, Hooks - Property 'state' does not exist on type

I'm trying to create a simple todo app using React, typescript and hooks useContext and useReducer.

index.tsx

import React, { useContext, useReducer } from "react";
import ReactDOM from "react-dom";
import "./index.css";

import TodosContext from "./context";
import todosReducer from "./reducer";
import TodoList from "./components/TodoList";
import { ITodo } from "./context";

const App = () => {
  const initialState = useContext(TodosContext);
  const [state, dispatch] = useReducer(todosReducer, initialState);

  return (
    <TodosContext.Provider value={{ state, dispatch }}> <!-- error here --->
      <TodoList />
    </TodosContext.Provider>
  );
};

ReactDOM.render(
  <App />,

  document.getElementById("root")
);

Here I get error for state

Type '{ state: any; dispatch: Dispatch<any>; }' is not assignable to type '{ todos: { id: number; text: string; complete: boolean; }[]; }'.
  Object literal may only specify known properties, and 'state' does not exist in type '{ todos: { id: number; text: string; complete: boolean; }[]; }'.ts(2322)

TodoList.tsx

import React, { useContext } from "react";
import TodosContext from "../context";
import { ITodo } from "../context";
import { initialState } from "../context";

export default function TodoList() {
  const { state } = useContext(TodosContext); <!-- error here --->

  return (
    <div>
      <ul>
        {state.todos.map(todo => (
          <li key={todo.id}>
            <span>{todo.text}</span>
            <button>edit</button>
            <button>delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Here I get a the same error for state

Property 'state' does not exist on type '{ todos: { id: number; text: string; complete: boolean; }[]; }'.ts(2339)

context.tsx

import React from "react";

export interface ITodo {
  id: number;
  text: string;
  complete: boolean;
  state?: any; <!-- state is included in the interface --->
}

export const initialState = [
  { id: 1, text: "todo 1", complete: false },
  { id: 2, text: "todo 2", complete: false },
  { id: 3, text: "todo 3", complete: true }
];

const TodosContext = React.createContext({
  todos: [
    { id: 1, text: "todo 1", complete: false },
    { id: 2, text: "todo 2", complete: false },
    { id: 3, text: "todo 3", complete: true }
  ]
});

export default TodosContext;

reducer.tsx

export default function reducer(state: any, action: any) {
  switch (action.type) {
    default:
      return state;
  }
}

I have added state to the ITodo interface to see if that helped, but it doesn't.

How do I add state to the type

Upvotes: 5

Views: 12997

Answers (1)

petraszd
petraszd

Reputation: 4297

There two errors. And they are different kind of errors. First issue:

const { state } = useContext(TodosContext);

TodosContext has been created using some type and it returns that type of object after calling useContext. Uses explicit types to better understand how it works:

interface ITodosContextData {
  todos: ITodo[];
}
const TodosContext = React.createContext<ITodosContextData>(initialState);
const state: ITodosContextData = useContext(TodosContext);

You are using spread operator { key1, key2, key3 } on ITodosContextData. ITodosContextData does not have member state. What you actually want is this:

const state = useContext(TodosContext);

Second issue is similar TodosContext.Provider.value is of type ITodosContextData. And you are providing some ad-hoc data object with different type.

Use:

const [state, dispatch] = useReducer(todosReducer, initialState);
<TodosContext.Provider value={state}>

to fix your problem.

Upvotes: 7

Related Questions