React with TypeScript β Build Safer & Scalable Apps (2025 Guide)
Introduction β Why Use TypeScript with React?
TypeScript enhances React development by adding static typing, autocomplete, and compile-time error detection. It enables:
- Safer code through type checking
- Smarter developer tooling and IDE support
- Better documentation and component contracts
TypeScript is now the industry standard for large React apps at companies like Microsoft, Meta, and Shopify.
In this guide, youβll learn:
- How to set up a React + TypeScript project
- Type your components, props, state, events, and hooks
- Use generics, enums, and utility types
- Best practices and tips for scalable TSX code
1. Setup β Create a React + TypeScript Project
With Vite (Recommended):
npm create vite@latest my-app -- --template react-ts
With Create React App (CRA):
npx create-react-app my-app --template typescript
You’ll get .tsx support and tsconfig.json automatically.
2. Basic Component Typing
Functional Component with Props:
type GreetingProps = {
name: string;
age?: number; // optional prop
};
const Greeting: React.FC<GreetingProps> = ({ name, age }) => (
<p>Hello, {name}! {age && `Age: ${age}`}</p>
);
Type safety for consumers
Autocomplete for props in JSX
3. useState & useEffect Typing
const [count, setCount] = useState<number>(0);
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
console.log('Count changed:', count);
}, [count]);
Always annotate complex types like null, objects, or arrays
Optional: let TypeScript infer types for primitives
4. Typing Events in React
Input Change Event:
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setValue(e.target.value);
};
Form Submit:
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
// submit logic
};
Use React.*Event for DOM event types
5. Children and FC Typing
type CardProps = {
children: React.ReactNode;
};
const Card: React.FC<CardProps> = ({ children }) => (
<div className="card">{children}</div>
);
Enables Card to wrap any nested JSX content
6. Typing useRef and useReducer
useRef:
const inputRef = useRef<HTMLInputElement>(null);
useReducer:
type State = { count: number };
type Action = { type: 'increment' | 'decrement' };
const reducer = (state: State, action: Action): State => {
switch (action.type) {
case 'increment': return { count: state.count + 1 };
case 'decrement': return { count: state.count - 1 };
}
};
const [state, dispatch] = useReducer(reducer, { count: 0 });
Type-safe reducer patterns for complex state logic
7. Typing Custom Hooks
function useToggle(initial: boolean): [boolean, () => void] {
const [value, setValue] = useState(initial);
const toggle = () => setValue(v => !v);
return [value, toggle];
}
Explicit return types improve reusability
Encourages better API design
8. TypeScript Utility Types
| Utility Type | Description | Example |
|---|---|---|
Partial<T> | Makes all properties optional | Partial<User> |
Pick<T, K> | Selects a subset of properties | `Pick<User, ‘name’ |
Omit<T, K> | Excludes properties from type | Omit<User, 'password'> |
Record<K, T> | Creates an object type with keys K | Record<string, boolean> |
Readonly<T> | Makes fields immutable | Readonly<User> |
Great for forms, settings, feature toggles, etc.
9. Best Practices for React + TypeScript
Use .tsx for all components
Define Props types near the component
Avoid anyβuse unknown or strong typing instead
Use interface or type consistently (prefer type for components)
Type your API responses or use Zod/Yup for runtime validation
Use enum or union types for fixed values (e.g., button variants)
Summary β Recap & Next Steps
Using TypeScript with React provides robust typing, better tooling, and fewer bugs in the long run. Itβs ideal for scalable apps, component libraries, and enterprise teams.
Key Takeaways:
- Type props, state, events, and hooks for full coverage
- Prefer type-safe utilities over loose typing
- Avoid
anyand useinterfaceortypeconsistently - Type custom hooks and async APIs for reliability
- Use VS Code and ESLint to maximize productivity
Real-World Relevance:
React + TypeScript is used by Meta, Microsoft, Atlassian, and top open-source libraries for their component systems and production codebases.
FAQ Section
Should I use interface or type for props?
Both work. Use type for function signatures and union types; interface for extending object shapes.
How do I type API responses?
Use type User = Awaited<ReturnType<typeof fetchUser>> or tools like Zod to validate and infer types.
Is TypeScript required for React?
No, but it’s highly recommended for better safety, maintainability, and IDE support.
Can I use React Testing Library with TypeScript?
Yes! Most RTL APIs are fully typed. Add @testing-library/jest-dom for extended matchers.
How do I type dynamic component props?
Use union or discriminated unions for conditional props:
type Props = { type: 'text'; value: string } | { type: 'checkbox'; checked: boolean };
Share Now :
