Reputation: 768
I have the following generic custom hook made with typescript:
import { useState } from "react"
export const useForm = <T>(initialValues: T) => {
const[values, setValues] = useState<T>(initialValues)
return [
values,
(
e: { target: HTMLInputElement}) => {
setValues({
...values,
[e.target.name]: e.target.value
})
}
]
}
Then I'm trying to use it:
import React from 'react';
import { useForm } from './useForm';
type FormValues = {
email: string,
password: string
}
const App : React.FC = () => {
const initialValues: FormValues = {email: "", password: ""}
const [values, handleChanges] = useForm<FormValues>(initialValues);
return (
<div>
<input type="text" name="email" value={(values.email} onChange={e => handleChanges}/>
<input
type="password"
name="password"
value={values.password}
onChange={e => handleChanges}/>
</div>
)
}
My problem is around
values.email
and
values.password
The error message is:
Property 'email' does not exist on type 'FormValues | ((e: { target: HTMLInputElement; }) => void)'. Property 'email' does not exist on type '(e: { target: HTMLInputElement; })
Property 'password' does not exist on type 'FormValues | ((e: { target: HTMLInputElement; }) => void)'. Property 'password' does not exist on type '(e: { target: HTMLInputElement; })
If values is an unioun between FormValues and another value shouldn't I be able to access email and password from it?
Upvotes: 0
Views: 251
Reputation: 768
The problem is my return type. It seems I have to explicitly put it on the code signature.
import { useState } from "react"
import { ChangeEvent } from "react"
function useForm<T>(
initialState: T,
): [T, (e: ChangeEvent<HTMLInputElement>) => void] {
const [values, setValues] = useState<T>(initialState);
function handleChange(e: ChangeEvent<HTMLInputElement>): void {
setValues({
...values,
[e.target.name]: e.target.value,
});
}
return [values, handleChange];
}
export default useForm;
Upvotes: 2