TypeScript with React
11.1 Typing Props, State, and Hooks
Props (including children)
Think small, type precisely, and let defaults do the heavy lifting. Avoid defaultProps for function components-mark optionals explicitly and use parameter defaults.

When children is always welcome, bolt it on with PropsWithChildren.

useState
Inference is your friend-except when it isn’t. If you start with null or you need a literal union, add a generic.

useRef
DOM refs are nullable until mounted; value refs aren’t if you seed them.

useReducer
Give State and Action crisp shapes; use a discriminant for tidy narrowing.

Events and callbacks

forwardRef + useImperativeHandle
Expose a minimal, well-typed surface-nothing more.

11.2 Discriminated Unions & Component Overloads
Discriminated unions (the everyday workhorse)
One literal key. Mutually exclusive shapes. Exhaustive by design.

Usage:

Component overloads (when you truly need them)
Separate call-signatures for distinct prop contracts; union in the body.

Polymorphic “as” (generic alternative)
Type-safe element switching without a combinatorial explosion.

Rule of thumb: use discriminated unions by default; reach for overloads or polymorphic generics when the API surface genuinely varies.
11.3 Utility Types & Inference Patterns
React-aware helpers
Lean on React’s mapped helpers to avoid retyping what already exists.
- React.ComponentProps<"button"> – props for an intrinsic element.
- React.ComponentProps<typeof X> – props for X.
- ComponentPropsWithRef<T> / ComponentPropsWithoutRef<T> – include/exclude ref.
- React.ElementRef<typeof X> – ref target type.
- PropsWithChildren<P> – adds children?: ReactNode.

type PrimaryButtonProps = React.ComponentProps<typeof PrimaryButton>;
Core TypeScript transforms (perfect for props)
- Pick / Omit – carve out the shape you need.
- Partial / Required / Readonly – adjust optionality and mutability.
- Record<K, V> – tidy lookup tables (e.g., size → classes).
- Extract / Exclude – filter unions precisely.
- NonNullable – strip null/undefined.

Inference superpowers
Derive, don’t duplicate. Preserve literals. Enforce shape without widening.

Extending native props (safely)
Prefer composition with Omit to sidestep name clashes.

Correct ref forwarding

Bottom line: let inference lead, model exclusivity with discriminated unions, and reuse existing prop types with React/TypeScript utilities. You’ll ship safer components with less boilerplate-and your future self will thank you.
Here’s a key for the acronyms that appear in the article above (only those used there):
- JSX - JavaScript XML (syntax extension that looks like HTML inside JavaScript/TypeScript).
- TSX - TypeScript + JSX (the
.tsx file format used in the code samples). - DOM - Document Object Model (browser’s in-memory tree of the page).
- API - Application Programming Interface (the callable surface of a library/component).
- HTML - HyperText Markup Language (markup for web documents).
- TS - TypeScript (typed superset of JavaScript; referenced as “TS 4.9+”).
- UK - United Kingdom (used in an example option label).
- EU - European Union (used in an example option label).