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