Today, I learned that listening to the onChange
event is different in TypeScript-based React form components. Normally, the approach I'd take would look like this;
import React from 'react'
export default function FormComponent() {
const [name, setName] = React.useState('')
const handleNameChange = (event) => {
setName(event.target.value)
}
const doSomething = () => {
console.log('do something')
}
return (
<div>
<form>
<label htmlFor="name">
Name
<input
type="text"
value={name}
name="name"
placeholder="enter your name"
onChange={handleNameChange}
/>
</label>
<button type="button" onClick={doSomething}>
submit
</button>
</form>
</div>
)
}
And, that's all one would need to keep track of the state in the name
input field of this form component. But it is a bit different with TypeScript, because of its "type safety" perk.
the TypeScript approach
In TypeScript, here's what the component would look like. Pretty much the same thing, but the event handler function is different.
const FormComponent: React.FC = () => {
const [name, setName] = React.useState('')
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setUrl(event.target.value)
}
return (
<>
<FormMarkup />
</>
)
}
Here's how the snippet — especially the handler — above works;
The handler accepts an argument, (event: React.ChangeEvent<HTMLInputElement>)
which is its type signature, indicating that it accepts an event of type React.ChangeEvent<HTMLInputElement>
. Accepting the HTMLInputElement
means that we're expecting the ChangeEvent
interface to dispatch an event whenever there's a change in the value of an HTML input element.
TypeScript will enforce that the event
argument passed to handleNameChange
is of the correct type and that we can access the value
property of the input element without any runtime errors.
The event
parameter is an instance of the ChangeEvent
method from React. It contains the information about the change event that triggered the callback function — the handler function, in this case.
event.target
refers to the element that triggered the event, in this case, an <input>
element.
event.target.value
is the new value of the input element.
setName(event.target.value)
from the useState hook updates the state of the name
variable to the new value.
my thoughts?
I feel like this is just unnecessarily too "much", Lol, if we're, to be honest. But, the fact that we can define event handlers this way, and ensure type safety in our code is something i can refer to as "cool"
In JavaScript, one could accidentally pass the wrong type of event object to an event handler and not catch the error until runtime.
But, with TypeScript, as they say:
you get compile-time checks that help prevent these kinds of errors.
As always, I'll keep documenting my process with TypeScript here.