This lesson assumes basic TypeScript syntax is already familiar — types, interfaces, generics — and focuses specifically on the patterns unique to typing a React component. A .tsx file extension (instead of .jsx) is what tells the TypeScript compiler a file contains JSX.
interface ButtonProps {
label: string
onClick: () => void
disabled?: boolean // the ? makes this prop optional
}
function Button({ label, onClick, disabled }: ButtonProps) {
return (
<button onClick={onClick} disabled={disabled}>
{label}
</button>
)
}React's built-in ReactNode type covers anything valid as JSX children — text, elements, fragments, or nothing at all.
import type { ReactNode } from 'react'
interface CardProps {
title: string
children: ReactNode
}
function Card({ title, children }: CardProps) {
return (
<div className="card">
<h3>{title}</h3>
{children}
</div>
)
}TypeScript usually infers the type from the initial value — an explicit type argument is only needed when the initial value doesn't fully describe every state the variable can hold.
const [count, setCount] = useState(0) // inferred as number
const [name, setName] = useState('') // inferred as string
// Needs an explicit type — starts as null, but will later hold a User
const [user, setUser] = useState<User | null>(null)React provides typed versions of DOM events, prefixed with React. — event.target is then correctly typed too, instead of being any.
function SearchBox() {
const [query, setQuery] = useState('')
function handleChange(event: React.ChangeEvent<HTMLInputElement>) {
setQuery(event.target.value)
}
return <input value={query} onChange={handleChange} />
}function TextInput() {
const inputRef = useRef<HTMLInputElement>(null)
function focus() {
inputRef.current?.focus() // ?. because it starts as null
}
return <input ref={inputRef} />
}| What | How to type it |
|---|---|
| Props | An interface, destructured in the function's parameter |
| children | The ReactNode type |
| useState | Usually inferred; use useState |
| Event handlers | React.ChangeEvent |
| useRef to a DOM element | useRef |
Starting a project already typed
Most tooling that scaffolds a React project (including Vite) offers a TypeScript template out of the box — starting a new project with it from day one avoids retrofitting types onto existing JavaScript later.