Home > Net >  How to type payload and get the correct type from dispatch?
How to type payload and get the correct type from dispatch?

Time:12-23

I am building an User Form Step and when I try to type payload with the User's type I get a type error on my dispatch within the handleNameChange function.

This is my context.tsx file:

type User = {
  name: string;
  password: string;
  confirmPassword: string;
  email: string;
  birthDate: string;
  address: {
    zipCode: string;
    street: string;
    number: string;
    neighborhood: string;
    city: string;
    reference: string;
  };
};

type State = {
  currentStep: number;
  user: User;
};

type Action =
  | { type: FormActions.setCurrentStep; payload: number }
  | { type: FormActions.setUser; payload: User };

type ContextType = {
  state: State;
  dispatch: (action: Action) => void;
};

type FormProviderProps = {
  children: ReactNode;
};

const initialState: State = {
  currentStep: 0,
  user: {
    name: "",
    password: "",
    confirmPassword: "",
    birthDate: "",
    email: "",
    address: {
      zipCode: "",
      street: "",
      number: "",
      neighborhood: "",
      city: "",
      reference: "",
    },
  },
};

// Context
const FormContext = createContext<ContextType | undefined>(undefined);

// Reducer
export enum FormActions {
  setCurrentStep,
  setUser,
}

const formReducer = (state: State, action: Action) => {
  switch (action.type) {
    case FormActions.setCurrentStep:
      return { ...state, currentStep: action.payload };
    case FormActions.setUser:
      return { ...state, user: action.payload };
    default:
      return state;
  }
};

// Provider
export const FormProvider = ({ children }: FormProviderProps) => {
  const [state, dispatch] = useReducer(formReducer, initialState);
  const value = { state, dispatch };
  return <FormContext.Provider value={value}>{children}</FormContext.Provider>;
};

// Context Hook
export const useForm = () => {
  const context = useContext(FormContext);
  if (context === undefined) {
    throw new Error("useForm needs to be used inside FormProvider");
  }
  return context;
};

And this the component:

import { useForm, FormActions } from "../../contexts/FormContext";
import { ChangeEvent, useEffect } from "react";

export const FormStep1 = () => {
  const { state, dispatch } = useForm();

  useEffect(() => {
    dispatch({
      type: FormActions.setCurrentStep,
      payload: 1,
    });
  });

  const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
    dispatch({
      type: FormActions.setUser,
      payload: e.target.value,
    });
  };

  return (
    <S.Container>
      <input
        type="text"
        autoFocus
        value={state.user.name}
        onChange={handleNameChange}
      />
    </S.Container>
  );
};

The error is in the line:

  payload: e.target.value,

And says:

Type 'string' is not assignable to type 'number | User'. The expected type comes from property 'payload' which is declared here on type 'Action'

How can I type payload to be a string from the User's type?

CodePudding user response:

You need to specify that the payload is a User object in your handleNameChange function, and then update the name field in the user object:

const handleNameChange = (e: ChangeEvent<HTMLInputElement>) => {
  dispatch({
    type: FormActions.setUser,
    payload: {
      ...state.user,
      name: e.target.value,
    },
  });
};
  • Related