TypeScript with React
Typing a component and its props
Section titled “Typing a component and its props”A React component is a function, so you type it by typing its props. Define a type (or interface) for the props and annotate the parameter:
type ButtonProps = { label: string; onClick: () => void; variant?: 'primary' | 'secondary'; // optional, a literal union};
function Button({ label, onClick, variant = 'primary' }: ButtonProps) { return <button className={variant} onClick={onClick}>{label}</button>;}Prefer typing the props object directly (as above) over the older React.FC — React.FC has fallen out of favor (it complicates generics and children typing). Just annotate the destructured props parameter.
Children and common React types
Section titled “Children and common React types”When a component wraps other content, type children as React.ReactNode — the broadest “anything renderable” type:
type CardProps = { title: string; children: React.ReactNode; // JSX, strings, numbers, arrays, null…};
function Card({ title, children }: CardProps) { return <section><h2>{title}</h2>{children}</section>;}Other types you’ll reach for: React.ReactNode (renderable content), React.ComponentProps<'button'> (steal a host element’s props), and React.CSSProperties (a style object).
Typing hooks
Section titled “Typing hooks”Inference handles most hooks, but supply a type argument when the initial value doesn’t pin it down:
const [count, setCount] = useState(0); // inferred: numberconst [user, setUser] = useState<User | null>(null); // needs the annotation
const inputRef = useRef<HTMLInputElement>(null); // ref to a DOM nodeconst timer = useRef<number | undefined>(undefined); // ref to a mutable valueTyping events
Section titled “Typing events”Event handlers get typed event objects. Let contextual typing infer them inline where possible; annotate when you extract the handler:
function onChange(e: React.ChangeEvent<HTMLInputElement>) { console.log(e.target.value);}<button onClick={(e) => e.preventDefault()}>Go</button> // e inferred as React.MouseEventReact 19: ref is a normal prop
Section titled “React 19: ref is a normal prop”A concrete currency win: in React 19, ref is a regular prop for function components, so you no longer need forwardRef and its awkward generics. You type ref right alongside the other props:
// React 19 — ref is just a prop.type InputProps = { placeholder?: string; ref?: React.Ref<HTMLInputElement>;};
function TextInput({ placeholder, ref }: InputProps) { return <input placeholder={placeholder} ref={ref} />;}forwardRef still works and older code using React.forwardRef<HTMLInputElement, Props> is fine, but for new components in React 19 you skip it entirely — one fewer wrapper and no generic gymnastics.