🧠 Mastering TypeScript in React: From Red Squiggles to Confidence
When you’re building maintainable and scalable React applications, TypeScript is one of the most valuable tools in your developer toolbox. It offers safety, productivity, and clarity — even if it seems strict or frustrating at first.
But remember:
“TypeScript is not making your life terrible. It’s just showing you how terrible your life already is.” – Kent C. Dodds
Let’s walk through how to use TypeScript effectively in React — from typing components and props, to improving developer experience with narrowing, deriving, and even satisfying types. 🦺
Think of TypeScript as a brutally honest friend. It points out the problems before your users run into them — the “spinach in your teeth” of your codebase.
Once you get past the initial learning curve, TypeScript becomes a key ally in reducing bugs and making your codebase easier to navigate and refactor.
Let’s start with the basics: typing regular functions.
// JS functionfunction getName(user) {return user.name ?? 'Unknown'}// With typestype User = { name?: string }function getName(user: User): string {return user.name ?? 'Unknown'}
TypeScript will infer return types in many cases, but specifying them makes your code more readable and robust.
📘 Learn More: TypeScript Function Syntaxes
React components are just functions. That means you can type them the same way:
type MessageProps = { children: React.ReactNode }function Message({ children }: MessageProps) {return <div className="message">{children}</div>}
You can also inline props or destructure them for conciseness:
function Message({ children }: { children: React.ReactNode }) {return <div className="message">{children}</div>}
📘 Resource: React + TypeScript Cheatsheets
Let’s say we have a Calculator
component:
<Calculator left={2} operator="**" right={3} /> // 💥 runtime error!
The problem? The operator
prop is typed as string
, which is too broad.
Instead, narrow it:
type Operator = '+' | '-' | '*' | '/'
Now TypeScript will complain if someone tries to use an unsupported operator.
type CalculatorProps = {left: numberright: numberoperator: Operator}
This makes your component API safer and more discoverable.
typeof
and keyof
Avoid repeating yourself by deriving prop types directly from objects.
const operations = {'+': (a: number, b: number) => a + b,'-': (a: number, b: number) => a - b,'*': (a: number, b: number) => a * b,'/': (a: number, b: number) => a / b,}type Operator = keyof typeof operations
Now, if you add a new operation to the operations
object, TypeScript automatically includes it in the Operator
type.
📘 More on typeof
📘 More on keyof
Want to make props optional with defaults?
type CalculatorProps = {left?: numberright?: numberoperator?: Operator}function Calculator({left = 0,right = 0,operator = '+',}: CalculatorProps) {const result = operations[operator](left, right)return <div>{result}</div>}
Now, this is valid:
<Calculator /> // Renders 0 + 0 = 0
Record
Instead of typing each operation function manually:
const operations = {'+': (a: number, b: number) => a + b,'-': (a: number, b: number) => a - b,// ...}
Use Record
:
type OperationFn = (a: number, b: number) => numbertype Operator = '+' | '-' | '*' | '/'const operations: Record<Operator, OperationFn> = {'+': (a, b) => a + b,'-': (a, b) => a - b,'*': (a, b) => a * b,'/': (a, b) => a / b,}
This avoids repeating function types, and helps TypeScript enforce structure.
satisfies
Using Record
works, but can sometimes widen types. You can fix that with satisfies
:
const operations = {'+': (a, b) => a + b,'-': (a, b) => a - b,'*': (a, b) => a * b,'/': (a, b) => a / b,} satisfies Record<Operator, OperationFn>
This ensures:
📘 TypeScript satisfies
operator
Sometimes, TypeScript can slow you down — and that’s OK. You can ask it to hush temporarily:
// @ts-expect-error I’ll fix this latermake.magic()
Don’t let the red squiggles keep you from making progress. TypeScript is here to help — not block you.
TypeScript makes your React applications more robust, self-documenting, and maintainable. Mastering it takes time, but step by step, you’ll gain confidence.
Here’s what you should walk away with:
typeof
+ keyof
helps derive types without repetition.Record
reduces redundancy.satisfies
enforces constraints without widening types.@ts-expect-error
when needed.📚 Keep these references handy:
💬 “You don’t have to get it perfect. Just get it going, and let TypeScript help guide you from there.”
Quick Links
Legal Stuff
Social Media