joequint22
joequint22

Reputation: 9

Using Typescript within React, and I'm having difficulty typing a useReducer function

Below is my Types file

type InputType = {
    one: string;
    two: string;
  };
  
 type ToDoType = {
    id: number,
    name: string,
    complete: boolean
};
  
 type ToDoAction = {
    type: string;
    payload: {
      name: string;
    };
  };

 type ToDoArray = ToDoType[];

 const ACTIONS = {
  //const because it holds as our object of actions
  ADD_TODO: "add-todo",
  TOGGLE_TODO: "toggle-todo",
  DELETE_TODO: "delete-todo",
};

I am receiving the error below. It is highlighted within the useReducer hook on the established reducer parameter itself... also receiving an error within my dispatch but i figured the root problem is within the useReducer function itself

No overload matches this call. Overload 1 of 5, '(reducer: ReducerWithoutAction, initializerArg: ToDoArray, initializer?: undefined): [ToDoArray, DispatchWithoutAction]', gave the following error. Argument of type '(todos: ToDoArray, action: ToDoAction) => ToDoArray | undefined' is not assignable to parameter of type 'ReducerWithoutAction'. Overload 2 of 5, '(reducer: ReducerWithoutAction, initialState: ToDoArray, initializer?: undefined): [ToDoArray, Dispatch]', gave the following error. Argument of type '(todos: ToDoArray, action: ToDoAction) => ToDoArray | undefined' is not assignable to parameter of type 'ReducerWithoutAction'.ts(2769)

import * as React from "react";
import { useState, useReducer, useEffect } from "react";
import Todo from "./components/Todo";
import "./App.css";
import  './components/Types'


function reducer(todos: ToDoArray, action: ToDoAction): ToDoArray | undefined{
  switch (action.type) {
    case ACTIONS.ADD_TODO:
      return [...todos, newToDo(action.payload.name)];
  }
}

function newToDo(name: string): ToDoType {
  return { id: Date.now(), name: name, complete: false };
}


function App() {

  const [todos, dispatch] = useReducer<React.ReducerWithoutAction<ToDoArray>>(reducer, [] as ToDoArray);
 
  const [userInput, setUserInput] = useState<InputType>({
    one: "",
    two: "",
  } as InputType);



  useEffect(() => {
    setTimeout((e: React.ChangeEvent<HTMLInputElement> ) => {
      setUserInput({ one: e.currentTarget.value, two: "" })
     }, 5000)
  }, [userInput.one])

  //UPDATES STATE onKEYSTROKE
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setUserInput({ one: e.currentTarget.value, two: "" });
  };

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    dispatch({ type: ACTIONS.ADD_TODO, payload: { name: userInput.one } });
    setUserInput({ one: "", two: "" });
  };


  

  return (
    <>
      <div className="App h-screen bg-red-400 flex justify-center items-center flex-col gap-8">
        <p
          className="title 
          text-5xl
          first-letter:font-bold 
          first-letter:text-white
          tracking-widest
          first-letter: ml-2
          
        "
        >
          TO-DO LIST
        </p>
        <form onSubmit={handleSubmit} className="">
          <input
            onChange={handleChange}
            id="xxx"
            type="text"
            value={userInput.one}
            className="
              input 
              w-72 
              rounded-sm 
              shadow-xl
              border-none 
              outline-none
              p-1"
          />
        </form>
        {todos.map((todo: ToDoType) => {
          <Todo id={todo.id} todo={todo} dispatch={dispatch} />;
        })}
      </div>
    </>
  );
}

export default App;

Upvotes: 0

Views: 61

Answers (1)

HindicatoR
HindicatoR

Reputation: 145

Copy the following solution :


type ReducerFn = (todos: ToDoArray, action: ToDoAction) => ToDoArray;

function reducer(todos: ToDoArray, action: ToDoAction): ToDoArray {
  switch (action.type) {
    case ACTIONS.ADD_TODO:
      return [...todos, newToDo(action.payload.name)];
    default: {
      return [];
    }
  }
}

and change the useReducer line to -

const [todos, dispatch] = useReducer<ReducerFn>(reducer, []);

and also the todos.map to

{todos.map((todo: ToDoType) => (
   <Todo id={todo.id} todo={todo} dispatch={dispatch} />
))}

Upvotes: 0

Related Questions