📚 Download my FREE 101 React Tips And Tricks Book for a head start.
Two weeks ago, I stumbled upon this post on Reddit: Should I learn React with TypeScript or JavaScript?
I see these posts all the time—and honestly, it breaks my heart 🥲
If you’re a React dev still using JavaScript, you’re making your life harder.
The time you spend learning TypeScript will 100% pay off in the time you save debugging weird bugs.
So here’s a guide to help you make the switch.
Just the essentials. No fluff 😉.
How TypeScript works
TypeScript adds extra syntax on top of JavaScript to help catch errors early—before they crash your app.
It compiles to JavaScript in the end.
The best part? You can slowly migrate to TypeScript.
Follow this guide for more.
Why you should switch to TypeScript ASAP
Here’s why I think it’s a no-brainer:
Benefit #1: Catch bugs before they reach production
This JavaScript code looks fine… until it explodes:
function printFirstChar(users, userIndex) {
const name = users[userIndex];
console.log(name[0]);
}
const users = ['Fatou', 'Bob'];
printFirstChar(users, 5); // ❌ Runtime error: Cannot read properties of undefined
Here’s the TypeScript version:
function printFirstChar(users: string[], userIndex: number) {
const name = users[userIndex];
if (name != null) {
console.log(name[0]);
}
}
TypeScript doesn’t fix your logic, but it gives you early warnings like “hey, this might be undefined 👀”
Benefit #2: Get autocompletion with libraries
Especially useful when you're exploring a new library.
If that library has TypeScript types, you can get autocompletion inside most editors.
Benefit #3: Make your code more resilient to changes
When you type things properly, TypeScript acts like a safety net.
For example:
Without TypeScript, this code can break without you noticing.
function getLabel(status) {
switch (status) {
case 'idle':
return 'Idle';
case 'loading':
return 'Loading';
case 'success':
return 'Success';
}
}
getLabel('loading'); // ✅ works
// Months later...
getLabel('error'); // ❌ returns undefined, but no JS error
With TypeScript, you need to handle changes.
type Status = 'idle' | 'loading' | 'success';
function getLabel(status: Status): string {
switch (status) {
case 'idle':
return 'Idle';
case 'loading':
return 'Loading';
case 'success':
return 'Success';
case 'error':
return 'Error';
}
}
// Months later...
type Status = 'idle' | 'loading' | 'success' | 'error'; // added 'error'
// ✅ TypeScript will show an error for the `getLabel` function: "Not all code paths return a value"
If you forget to handle a case, TypeScript yells at you. And that’s precisely what you want 😄.
TypeScript error when we forget to handle a case
The TypeScript concepts you need for React
Let’s cover the bare minimum to get started.
✅ Types
Types let you describe the shape of your data and enforce it.
There are native types in TypeScript, and types defined by users.
Native types
These types come by default.
const name = 'Ada'; // string
const age: number = 31; // number
const isActive = true; // boolean
const scores: number[] = [90, 85, 100]; // number[]
💡 In some of the examples above, I typed values explicitly (like
const age: number = 31
).You don’t need to do that in real code—TypeScript can infer the types by looking at the values.
Custom types
You can create new types using the native types.
type User = {
id: number;
name: string;
};
const user: User = {
id: 1,
name: 'Fatou',
};
❌ Avoid any
Unless you’re in the middle of a migration, don’t use any
.
It’s JavaScript in disguise.
Use unknown
instead—it forces you to check the type before using it.
// ❌ Bad: no warning, crashes at runtime
function logLength(value: any) {
console.log(value.length);
}
logLength(123);
// ✅ Safer
function logLength(value: unknown) {
if (typeof value === 'string' || Array.isArray(value)) {
console.log(value.length);
}
}
// ✅✅ Better: use an explicit type
function logLength(value: string | ArrayLike<unknown>){
console.log(value.length);
}
🧩 Union & intersection types
Unions let a value be one of many types.
type Status = 'idle' | 'loading' | 'error';
let currentStatus: Status = 'idle';
Intersections combine multiple types into one.
type Name = { name: string };
type Age = { age: number };
type Person = Name & Age;
const person: Person = { name: 'Ada', age: 30 };
🧱 Interfaces
Interfaces define the structure of an object.
interface User {
name: string;
age: number;
}
You can extend interfaces:
interface Admin extends User {
role: string;
}
When to use type
vs interface
? Doesn’t matter much.
But here’s an interesting guide:
👉 Type vs Interface: Which Should You Use?
🔁 Generics
Generics let you write reusable types with flexible data.
Let’s say you’re typing an API response.
Without generics:
type UserResponse = {
status: number;
data: User;
error?: string;
};
type ProductResponse = {
status: number;
data: Product;
error?: string;
};
That’s a lot of repetition.
With generics:
type ApiResponse<T> = {
status: number;
data: T;
error?: string;
};
type UserResponse = ApiResponse<User>;
type ProductResponse = ApiResponse<Product>;
You can use generics in functions too:
function wrap<T>(value: T): T[] {
return [value];
}
wrap(42); // type: number[]
wrap('hi'); // type: string[]
I like to think of generics like function parameters—but for types 😉.
🔧 Function types
You can type function parameters and return values.
You always need to type the parameters, but don’t need to type the returned value every time.
// This works
function add(a: number, b: number): number {
return a + b;
}
// This also works: you don't need to type the returned value
function add(a: number, b: number) {
return a + b; // inferred as number
}
You can also type the function variable:
const add: (a: number, b: number) => number = (a, b) => a + b;
Depending on the context, you may want to type the return type. When in doubt, type the return type.
You can learn more about return types here:
How to use TypeScript with React
Props
Props are just objects. Type them like any other object.
With type
:
type GreetingProps = {
name: string;
};
function Greeting({ name }: GreetingProps) {
return <p>Hello {name}</p>;
}
With interface
:
interface GreetingProps {
name: string;
}
function Greeting({ name }: GreetingProps) {
return <p>Hello {name}</p>;
}
State
useState
accepts a generic type, but TypeScript can also infer it.
const [count, setCount] = useState(0); // inferred as number
But if it can’t, be explicit:
const [user, setUser] = useState<{ id: number; name: string } | null>(null);
Component variables and functions
Just like normal TypeScript:
const users: User[] = [{name: "Fatou", age: 31}, {name: "Bob", age: 25} ];
const age = 30; // inferred as number
When you have some functions like event handlers, you can hover over the DOM elements to see the types to use.
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
console.log('Clicked!', event);
};
// Or:
const handleClick: React.MouseEventHandler<HTMLButtonElement> = (event) => {
console.log('Clicked!', event);
};
Re-using types across components
You can extend or combine types/interfaces to avoid duplication.
With interfaces:
interface ButtonProps {
label: string;
}
interface IconButtonProps extends ButtonProps {
icon: React.ReactNode;
}
With union types:
type ButtonProps = {
label: string;
};
type IconButtonProps = ButtonProps & {
icon: React.ReactNode;
};
Hooks
Hooks are just functions, so you can use the same TypeScript tools that apply to functions.
Native hooks
Pretty much all the native hooks have generic params.
const [count, setCount] = useState<number>(0);
// or let TS infer:
const [count, setCount] = useState(0);
const inputRef = useRef<HTMLInputElement>(null);
const [state, dispatch] = useReducer(
(state: number, action: 'inc' | 'dec') => {
switch (action) {
case 'inc':
return state + 1;
case 'dec':
return state - 1;
}
},
0
);
Custom hooks
function useToggle(initial: boolean): [boolean, () => void] {
const [state, setState] = useState(initial);
const toggle = () => setState((prev) => !prev);
return [state, toggle];
}
const [isOpen, toggleOpen] = useToggle(false);
Where to learn more
If you want to go deeper with TypeScript, here are some great resources to explore:
🧠 TypeScript Official Docs: The best place to start. It’s clear, well-structured, and packed with examples. Also includes a playground to test things out.
🎯 Total TypeScript: A fantastic site by Matt Pocock—especially for React devs.
It has a free beginner course, advanced patterns, and many real-world examples.✨ TypeScript Style Guide: Short, practical tips on how to write clean and consistent TypeScript code. Highly recommended once you start building real apps.
🧩 Type Challenges: A collection of TypeScript puzzles—from beginner to insane. Great if you learn best by solving problems and want to flex your type system skills.
📘 Effective TypeScript: A book + blog by Dan Vanderkam. More advanced, but teaches you how to write better TypeScript. Worth it once you know the basics.
⚛️ React TypeScript Cheatsheets: Tailored for React devs. Covers everything from typing components to context and hooks. Very beginner-friendly, and super helpful as a quick reference.
💡 Make sure to also check out the TypeScript section of my 101 React Tips & Tricks post 😉.
Summary
Using TypeScript with React is one of the best upgrades you can make.
It helps you catch bugs early, gives you better tooling, and makes your code easier to maintain.
The best part? You don’t need to learn everything up front. Start with the basics—types, interfaces, generics—and grow from there.
Many examples are online if you get stuck, and AI tools can help you unblock fast.
Let me know if you have any questions 🙂.
<iframe src="https://embeds.beehiiv.com/4b52f101-5150-4e42-abc6-28785fdd68cd" data-test-id="beehiiv-embed" width="100%" height="320" frameborder="0" scrolling="no" style="border-radius: 4px; border: 2px solid #e5e7eb; margin: 0; background-color: transparent;"></iframe>
That's a wrap 🎉.
Leave a comment 📩 to join the discussion.
And don't forget to drop a "💖🦄🔥".
If you're learning React, download my 101 React Tips & Tricks book for FREE.
If you like articles like this, join my FREE newsletter, FrontendJoy.
Top comments (15)
But I like it, learning TypeScript for React feels like adding training wheels when riding a new bikemakes the trip smoother and you fall less; but what happens if you never take the training wheels off?
I really like the analogy!
The nice thing here is that you never have to take the wheels off (except maybe in interviews and I agree it is painful in that case 😅)
I will be honest, I like the idea of this article a lot.
But maybe improve first example for "Benefit #1: Catch bugs before they reach production" that if statement in typescript snippet could of been as easily used in javascript example with out typescript reference... Nothing about this screams typescript specific... change, so maybe reword it so it is obvious, that this IF statement was added after typescript suggested it?
Might be just me, but thats how I read it at first.
Thanks a lot for the input!
So name[0] will throw in JS but in TS, you will automatically see the warning in the IDE :)
Does it make more sense?
Yeah, anything to remove magic, and assumption, especially for those who otherwise do not know better.
Thank you, very helpful for learning more about ts
Visit my post here dev.to/jutionck/difference-between...
Thanks for sharing
Glad you like it ❤️
Some cool tips! You should share it on Daily (squads)... this type of tutorial based articles are always super valuable.
Thanks a lot! What are daily squads?
Check this: app.daily.dev/squads/discover
Communities on daily.dev based on interests.
Oh thanks a lot for sharing! I do see those but I find it hard sometimes to have the right to post 😅. Do you recommend one?
It totally depends on the topic but you can definitely share it in my squad. That’s where I post all of my articles on Daily.
I can’t really comment on the reach, since the algorithm changes from time to time... so try and see which squads give you better results.
Thanks a lot for sharing these 😃
Some comments may only be visible to logged-in visitors. Sign in to view all comments.