Dev.to WebDev 🛠 Dev 👁 0 📖 5 min read

React Mastery Series – Day 21: TypeScript with React – Building Type-Safe Applications

Welcome back to the React Mastery Series! In the previous article, we explored Production-Ready React Architecture and learned how enterprise applications are structured using: Feature-based architecture Service layer

Welcome back to the React Mastery Series!

In the previous article, we explored Production-Ready React Architecture and learned how enterprise applications are structured using:

  • Feature-based architecture
  • Service layers
  • Custom Hooks
  • State management
  • Scalable folder organization

Today, we will explore one of the most important skills for modern React developers:

TypeScript with React

Most enterprise React applications today are built using:

React + TypeScript

because TypeScript helps developers write:

  • Safer code
  • More maintainable applications
  • Better developer experiences
  • Fewer runtime errors

What is TypeScript?

TypeScript is a programming language built on top of JavaScript.

It adds:

  • Static typing
  • Interfaces
  • Generics
  • Type checking
  • Better IDE support

JavaScript:

let age = 30;
age = "thirty";

JavaScript allows this.

The error appears only at runtime.

TypeScript:

let age: number = 30;
age = "thirty";

Compiler error:

Type 'string' is not assignable to type 'number'

The problem is detected before running the application.

Why Use TypeScript with React?

Large React applications contain:

  • Hundreds of components
  • Multiple developers
  • Complex data flows
  • API integrations

Without types:

Component
    |
    ↓
Unknown Data
    |
    ↓
Runtime Error

With TypeScript:

Component
    |
    ↓
Typed Data
    |
    ↓
Compile-Time Validation

Creating a React TypeScript Project

Using Vite:

npm create vite@latest my-app

Select:

React
TypeScript

or:

npx create-react-app my-app --template typescript

TypeScript File Extensions

React projects use:

.js
.jsx

for JavaScript.

TypeScript uses:

.ts
.tsx

.tsx is used for React components.

Example:

Button.tsx
Dashboard.tsx
App.tsx

Typing React Components

JavaScript component:

function Welcome() {
  return <h1>Hello</h1>;
}

TypeScript component:

function Welcome(): JSX.Element {
  return <h1>Hello</h1>;
}

The return type tells TypeScript:

"This component returns JSX."

Typing Component Props

One of the most common TypeScript use cases.

JavaScript:

function User({ name, age }) {
  return <h2>{name}</h2>;
}

Problem:

TypeScript does not know:

  • What type is name?
  • What type is age?

Create an interface:

interface UserProps {
  name: string;
  age: number;
}

Use it:

function User({name, age }: UserProps){
 return ( <h2> {name} - {age} </h2>);
}

Now:

<User name="Siva" age={30} />

works.

Incorrect:

<User name={100} age="thirty" />

TypeScript catches the error.

Optional Props

Sometimes props are optional.

Example:

interface UserProps {
  name: string;
  age?: number;
}

Now:

<User name="Siva"/>

is valid.

Default Props with TypeScript

Example:

interface ButtonProps {
  text?: string;
}

Component:

function Button({ text="Submit"}:ButtonProps){
  return (<button> {text} </button>);
}

Typing useState

React state should also have types.

Without type:

const [count,setCount] = useState(0);

TypeScript automatically understands:

count → number

For complex values:

interface User {
 id:number;
 name:string;
 email:string;
}


const [user,setUser] = useState<User | null>(null);

Meaning:

Initially:

user = null

Later:

user = User object

Typing Arrays

Example:

interface Product {
 id:number;
 name:string;
 price:number;
}


const [products,setProducts] = useState<Product[]>([]);

Now TypeScript knows:

products is an array of Product

Typing Events

React events also need types.

Example:

Input change:

function handleChange(event: React.ChangeEvent<HTMLInputElement>){
 console.log(event.target.value);
}

Usage:

<input onChange={handleChange} />

Button click:

function handleClick(event:React.MouseEvent<HTMLButtonElement>){
  console.log("Clicked");
}

Typing Forms

Example:

const handleSubmit = (event:React.FormEvent<HTMLFormElement>)=> {
 event.preventDefault();
}

Typing useRef

Example:

Accessing input element:

const inputRef = useRef<HTMLInputElement>(null);

Usage:

inputRef.current?.focus();

The ? protects against null values.

Typing useReducer

Earlier we learned:

State + Action = Reducer

With TypeScript:

State:

interface State {
 count:number;
}

Action:

type Action = { type:"increment"} | {type:"decrement"};

Reducer:

function reducer(state:State, action:Action):State {
  switch (action.type) {
    case "increment":
      return {
        count: state.count + 1,
      };

    case "decrement":
      return {
        count: state.count - 1,
      };

    default:
      return state;
  }
}

Typing API Responses

Enterprise applications heavily depend on APIs.

Example response:

{
"id":101,
"name":"Siva",
"role":"Developer"
}

Create interface:

interface Employee {
  id:number;
  name:string;
  role:string;
}

API call:

const response:Employee = await getEmployee();

Now components know exactly what data they receive.

Creating Reusable Generic Components

TypeScript becomes powerful with generics.

Example:

Reusable Table:

interface TableProps<T>{
 data:T[];
}

Now the table can display:

Users:

<Table<User> data={users} />

Products:

<Table<Product> data={products} />

Same component.

Different data types.

Type vs Interface

Both can define structures.

Interface:

interface User {
 name:string;
 age:number;
}

Type:

type User = {
 name:string;
 age:number;
}

Common practice:

Use:

  • interface for objects
  • type for unions and complex types

Union Types

Example:

type Status = "loading" | "success" | "error";

Usage:

const status:Status="loading";

Only allowed values:

loading
success
error

React Context with TypeScript

Example:

interface AuthContextType {
 user:User|null;
 login:()=>void;
 logout:()=>void;
}

Create context:

const AuthContext = createContext<AuthContextType | null>(null);

Now context usage becomes type-safe.

Enterprise Example: Banking Application

Imagine a transaction dashboard.

API response:

interface Transaction {
 id:number;
 amount:number;
 date:string;
 status: "SUCCESS"| "PENDING" | "FAILED";
}

Component:

function TransactionList({transactions}:{transactions:Transaction[]}) {
  return (
    <>
      {transactions.map((transaction) => (
        <div>{transaction.amount}</div>
      ))}
    </>
  );
}

Benefits:

  • Developers know the data structure
  • IDE provides autocomplete
  • Errors are caught early

Common Mistakes

1. Using "any" Everywhere

Avoid:

let data:any;

Because it removes TypeScript benefits.

2. Ignoring Null Values

Incorrect:

user.name

when user can be null.

Correct:

user?.name

3. Over-typing Simple Values

Avoid unnecessary complexity.

Example:

const count:number = 0;

Usually:

const count = 0;

is enough.

TypeScript Best Practices

  • Define interfaces near the feature where they are used.
  • Avoid using any.
  • Type API responses.
  • Use reusable types.
  • Use strict mode.
  • Prefer meaningful type names.
  • Keep types organized.

TypeScript Project Structure

A scalable approach:

src

├── types
│   ├── user.ts
│   ├── api.ts
│
├── features
│   └── transactions
│       ├── components
│       ├── services
│       └── types.ts

Key Takeaways

Today, we learned:

✅ TypeScript adds safety to React applications.
✅ Interfaces define component contracts.
✅ Props, state, events, and APIs can be strongly typed.
✅ Generics help create reusable components.
✅ TypeScript improves maintainability in enterprise projects.
✅ React + TypeScript is the preferred stack for modern applications.

Coming Next 🚀

In Day 22, we will explore:

React State Management with Redux Toolkit – Building Enterprise Applications

We will learn:

  • Why Redux exists
  • Redux architecture
  • Store
  • Actions
  • Reducers
  • Slices
  • Redux Toolkit
  • Async API calls
  • Middleware
  • Real-world enterprise examples

Redux Toolkit is one of the most widely used state management solutions in large-scale React applications.

Happy Coding! 🚀

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.