Reputation: 79
i'm just started learning Typescript. I trying to migrate a project from Javascript, but I got stuck with a custom hook.
The hook, useForm, just handle the onChange event of inputs in a form and then updates their values so I can write in and control their states.
interface formProps{
initialValues: {[key: string]: string}
}
export const useForm = ( initialState: formProps['initialValues'] ) => {
const [values, setValues] = useState(initialState);
const reset = () => {
setValues(initialState);
}
const handleInputChange = ({ target }: React.ChangeEvent<HTMLInputElement>) =>{
setValues({
...values,
[target.name]:target.value
})
}
return [values, handleInputChange, reset]
}
The argument for useForm should be an object with different entries, but the problem is it could be different any time, so I can't specify this.
When I try to use the hook in a component with for example values.userID
or values['password`]
I get the error:
The property 'password' does not exist on type '{ [key: string]: string; } | (({ target }: ChangeEvent) => void)'
How could I fix this? Thanks in advance!
Edit: I extract the values from 'values' with:
const [values, handleInputChange] = useForm({userID: '', password: ''})
Upvotes: 0
Views: 45
Reputation: 79
I got it working using:
import { useState } from "react";
interface InitialStateTypes {
[key: string]: string;
}
export const useForm = (initialState: InitialStateTypes): [InitialStateTypes, ({ target }: React.ChangeEvent<HTMLInputElement>) => void, ()=> void] => {
const [values, setValues] = useState(initialState);
const reset = () => {
setValues(initialState);
}
const handleInputChange = ({ target }: React.ChangeEvent<HTMLInputElement>) =>{
setValues({
...values,
[target.name]:target.value
})
}
return [values, handleInputChange, reset]
}
And I can access the values from 'values' using values['value']
instead of values.value
.
Upvotes: 0
Reputation: 191976
I would use generics to type the state according to the initial state, and return an object, so TS can easily infer the types (TS playground):
import React, { useState, ChangeEventHandler, ChangeEvent } from 'react';
export const useForm = <T extends Record<string, string>>( initialState: T ) => {
const [values, setValues] = useState(initialState);
const reset = () => {
setValues(initialState);
};
const handleInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
setValues({
...values,
[target.name]:target.value
});
};
return { values, handleInputChange, reset };
}
const { values, handleInputChange } = useForm({ userID: '', password: '' });
values['userID'] = 'x';
values['password'] = 'y';
Upvotes: 2