How to avoid casting [[form]].elements
typescript
When you do an uncontrolled form in React and you want to access a field inside of the elements
attribute, for instance username
, you'll get an error like this:
Property 'username' does not exist on type 'FormElements'
You can extend HTMLFormControlsCollection
and HTMLFormElement
to add all the input elements like this:
interface FormElements extends HTMLFormControlsCollection {
username: HTMLInputElement;
}
interface UsernameFormElement extends HTMLFormElement {
readonly elements: FormElements;
}
function UsernameForm({
onSubmitUsername,
}: {
onSubmitUsername: (value: string) => void;
}) {
const [error, setError] = React.useState<string | null>(null);
function onSubmit(evt: React.FormEvent<UsernameFormElement>) {
evt.preventDefault();
onSubmitUsername(evt.currentTarget.elements.username.value);
}
function onChange({
currentTarget: { value },
}: React.ChangeEvent<HTMLInputElement>) {
const isLowerCase = value === value.toLowerCase();
setError(isLowerCase ? null : "Username must be lower case");
}
return (
<form onSubmit={onSubmit}>
<div>
<label htmlFor="username">Username:</label>
<input id="username" onChange={onChange} />
</div>
<div role="alert" style={{ color: "red" }}>
{error}
</div>
<button type="submit" disabled={Boolean(error)}>
Submit
</button>
</form>
);
}
That way you avoid casting the elements
object.
I learnt this from @kentcdodds