You know what? I used to think “React vs TypeScript” made sense as a face-off. Like two tools in a ring. But that’s not how it works. React builds what you see. TypeScript checks the code you write. They’re different. Still, I’ve run projects with plain React, and projects with React + TypeScript. The feel is night and day.
If you’d like the unabridged soap-opera version of that first week, I break it down blow-by-blow in React vs TypeScript: My Hands-On Take From a Real Project Mess.
So…what are they?
- React: a UI library. It draws the screen, updates it, and gives you hooks and components. Buttons, lists, forms—the fun stuff.
- TypeScript: a typed layer on top of JavaScript. It catches mistakes before your app runs. Think spell-check, but for code.
Simple. And yet, this pairing changed how my week felt.
The bug that made me switch
I built a small plant shop for a friend. We called it Leafy Lane. Cute name. React only. No TypeScript. I was moving fast. I had a cart page that added price and tax. It worked…until it didn’t.
Here’s the silly code I shipped:
const price = "199";
const tax = "10";
const total = price + tax; // "19910" … oops
I didn’t notice right away. A customer did. They messaged, “Why is my total 19910?” My stomach sank. It was a string bug. Basic, but costly.
Now look at the same thing with TypeScript:
const price: number = 199;
const tax: number = 10;
const total = price + tax; // 209, clean
If I try to mix a string and a number, TypeScript yells before I even run the app. I like that kind of yelling. It saves me from late-night panic.
Props that lie (and how TS called them out)
Another one. I had a Button that used a label and an onClick handler. With plain React, I did this:
function Button({ label, onClick }) {
return <button onClick={() => onClick(label)}>{label}</button>;
}
// Later...
<Button label="Buy" onClick={(n) => console.log(n + 1)} /> // trouble
“Buy” is a string. The handler expects a number. JavaScript lets it slide. It fails at runtime.
My TypeScript rewrite:
type ButtonProps = {
label: string;
onClick: (label: string) => void;
};
function Button({ label, onClick }: ButtonProps) {
return <button onClick={() => onClick(label)}>{label}</button>;
}
// Now this fails at build time:
<Button label="Buy" onClick={(n: number) => console.log(n + 1)} />;
The error shows up in my editor. I fix it in seconds. No mystery bug. No guessing.
Day 1 speed vs week 4 speed
Here’s the thing: React alone feels fast on day one. You code. You see a button. Done. But week four? You trip on small stuff. I did, again and again.
React + TypeScript feels slower on day one. You add types. You think a bit more. But week four? You’re calm. The editor helps you. The app feels solid. My commits got smaller. My fixes got simpler.
Autocomplete that feels like a teammate
When I built a dashboard with charts, I used React + TypeScript + Vite. My API returned “orders.” With plain JS, I’d forget field names. Was it “orderId” or “id”? I’d guess, run, fail, sigh.
With TypeScript, I wrote:
type Order = {
id: string;
total: number;
createdAt: string;
};
function OrderRow({ order }: { order: Order }) {
return <div>{order.total}</div>;
}
Now my editor knows “order.total” is a number. If I type “order.totla” by mistake, it flags it at once. Feels small. Saves hours.
And when I do need to rename a field, I lean on the pattern I walk through in Renaming a TypeScript field and keeping JSDoc.
Hooks I trust more with types
A few spots where TypeScript helped me breathe:
-
useState with clear shape:
type User = { id: string; name: string } | null; const [user, setUser] = useState<User>(null);No “undefined” surprise later.
-
Event values in forms:
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { setAmount(Number(e.target.value)); };No “value is maybe null” drama.
-
useRef for elements:
const inputRef = useRef<HTMLInputElement | null>(null);I don’t poke at a ref like it’s always there. It might be null. TS makes me check.
When you step outside React and start building plain classes, giving your constructors named arguments can keep that same clarity—here’s my take on how to do that cleanly in TypeScript.
A small team story (and a coffee spill)
I had two interns on a React app. First week, we used plain React. I spent so much time in PRs saying, “This can be undefined,” or “This returns an object, not an array.” I got short. Coffee spilled. Not proud.
We switched to React + TypeScript the next sprint. Our PRs got shorter. The review chat turned into real design talk, not shape talk. The codebase felt teachable. New folks ramped faster. I didn’t change as a person. The guardrails helped me act better.
Where TypeScript fought me
It’s not all sunshine. TypeScript can be loud. Sometimes I just want to map over data and move on.
If the humble forEach is giving you grief, I give it a reality-check in my honest take on the TypeScript forEach loop.
My rule now:
- Type the public edges: API calls, props, context, hooks.
- Be light inside small functions. If it’s obvious, let the compiler infer it.
- Avoid “any.” But if I must use it—wrap it and fix it later.
Even something as simple as a file-path string deserves a real type. I show the lightweight way to do that in this article on giving a TypeScript file-path argument some love.
This keeps the noise low. If you’re looking for a broader set of guardrails and suggestions, I recommend skimming through the insights in the Using TypeScript with React: Best Practices article—they align closely with what I landed on during this project.
For the moments when types aren't enough and you need a quick note for future-you, I share the comment styles that have actually aged well in Comments in TypeScript: My Real-World Take.
Tooling that didn’t hurt
What I used and liked:
- Vite for React + TypeScript. Fast starts. Easy builds.
- ESLint + TypeScript rules. Catches silly stuff as I type.
- Zod or Yup to validate API data at runtime. Types help at build time; these help when the server lies.
None of this felt heavy once it was set.
If your next React + TypeScript side-project leans toward live video or chat features, it’s worth analyzing how established webcam platforms structure their flows. The in-depth Camster review breaks down the real-world UX patterns, latency tricks, and revenue hooks those sites rely on, giving you a solid checklist of ideas to borrow—or potholes to avoid.
Likewise, when your UI needs to support city-specific listings—think profiles, search filters, and clear calls to action—scanning a live directory can spark layout ideas; the Fairfield landing page on AdultLook showcases a straightforward grid and filtering sidebar that you can dissect for component patterns and user-flow cues.
If you’d like an even deeper dive into fine-tuning your React + TypeScript environment, I have a full walkthrough over on Improving Code. For a guided video-style setup, check out Setting Up: React and TypeScript | React with TypeScript | Steve Kinney.
When I’d choose each
If you’re asking “React vs TypeScript,” here’s how
