Skip to content
FrontendReactJs

TypeScript with React – Job-Ready Code लिखो (2026 Guide)

April 16, 2026 24 min read

नमस्ते दोस्तों! 🙏
स्वागत है The Easy Master पर!

क्या तुमने कभी सोचा है – React और TypeScript ek saath kyun use karte hain?

React apps बड़ा ho jata hai (50+ components), toh bugs aane lagte hain:

  • props mein wrong type pass ho jata hai
  • useState ka type TypeScript automatically detect nahi kar paata
  • API se aaya data undefined ho jata hai
  • Runtime errors production mein aa jaate hain

TypeScript with React Hindi में समझना बहुत जरूरी है क्योंकि:

  • 90% job descriptions TypeScript + React maangti hain
  • Companies like Microsoft, Google, Amazon TypeScript use karti hain
  • Bug 70% kam ho jaate hain
  • Developer experience – autocomplete, refactoring, documentation

Aaj kya seekhoge?

TopicKya Seekhega?
Why TypeScript + React?JavaScript vs TypeScript comparison
SetupVite + TypeScript project create
Component TypesReact.FC, Props, Children typing
Hooks TypinguseState, useEffect, useReducer, useContext
Event TypesonClick, onChange, onSubmit typing
API IntegrationAxios + TypeScript
Utility TypesReact-specific utility types
Job-Ready PatternsReal-world project structure

Kya tumhe pata hai?
TypeScript React 18+ ke saath perfect kaam karta hai. Vite TypeScript template ke saath setup sirf 1 minute mein hota hai!

तो चलिए शुरू करते हैं – TypeScript with React Hindi सीखने का सफर! 🚀



1. TypeScript with React – Introduction

TypeScript with React Hindi mein sabse pehle ye samajhna zaroori hai ki TypeScript React ko kaise better banata hai.

JavaScript vs TypeScript Comparison:c

Code
// ❌ JavaScript – No type safety
function UserCard({ user }) {
  // Kya user.name exist karta hai? Pata nahi!
  // user.age string hai ya number? Pata nahi!
  return (
    <div>
      <h3>{user.name}</h3>
      <p>Age: {user.age}</p>
    </div>
  );
}

// ✅ TypeScript – Complete type safety
interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

function UserCard({ user }: { user: User }) {
  // TypeScript guarantee karta hai ki user.name string hai
  // user.age number hai
  return (
    <div>
      <h3>{user.name}</h3>
      <p>Age: {user.age}</p>
    </div>
  );
}

// Wrong usage – TypeScript error dega!
// <UserCard user={{ name: "Rahul" }} /> // ❌ Error: missing email, age, id

TypeScript Benefits in React:

BenefitExplanation
Type SafetyProps, state, variables ka type fix
Better AutocompleteIDE suggestions
RefactoringSafe code changes
Self-documentingCode hi documentation hai
Compile-time errorsProduction mein runtime errors kam

2. Why TypeScript + React? (Benefits)

Real-world Scenario:

Code
// ❌ JavaScript – Runtime error production mein
function ProductList() {
  const [products, setProducts] = useState([]);
  
  useEffect(() => {
    fetchProducts().then(data => setProducts(data));
  }, []);
  
  return (
    <div>
      {products.map(product => (
        // Kya product.name exist karta hai? 
        // Kya product.price number hai?
        // Agar API ne price string bhej diya? 💥 Runtime error!
        <div key={product.id}>{product.name} - ${product.price}</div>
      ))}
    </div>
  );
}

// ✅ TypeScript – Compile-time error
interface Product {
  id: number;
  name: string;
  price: number;  // TypeScript ensure karega ki price number hai
}

function ProductList() {
  const [products, setProducts] = useState<Product[]>([]); // Type specified
  
  useEffect(() => {
    fetchProducts().then(data => setProducts(data));
    // Agar API ne price string bheja, TypeScript error dega
  }, []);
  
  return (
    <div>
      {products.map(product => (
        <div key={product.id}>{product.name} - ${product.price}</div>
      ))}
    </div>
  );
}

Developer Experience Benefits:

Code
// TypeScript se autocomplete magic
function Header({ user, onLogout, theme }) {
  // Jab tum "user." likhoge, IDE dikhayega:
  // - user.id
  // - user.name  
  // - user.email
  // - user.avatar
  // No need to remember!
  
  return (
    <header>
      <h1>Welcome, {user.name}</h1>
      <button onClick={onLogout}>Logout</button>
    </header>
  );
}

3. Setup – Vite + TypeScript Project

Step 1: Create Project

Code
# Vite + TypeScript template
npm create vite@latest my-app -- --template react-ts

# OR (yarn)
yarn create vite my-app --template react-ts

# OR (npm with specific version)
npm create vite@latest my-app -- --template react-ts

# Install dependencies
cd my-app
npm install

# Start development server
npm run dev

Step 2: Folder Structure

Code
my-app/
├── src/
│   ├── components/
│   │   ├── Button.tsx
│   │   ├── Button.module.css
│   │   └── index.ts
│   ├── pages/
│   │   ├── Home.tsx
│   │   └── About.tsx
│   ├── hooks/
│   │   └── useFetch.ts
│   ├── types/
│   │   └── index.ts
│   ├── services/
│   │   └── api.ts
│   ├── App.tsx
│   ├── main.tsx
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── package.json

Step 3: tsconfig.json Important Settings

Code
{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    
    /* Bundler mode */
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    
    /* Linting - Strict mode ON */
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

4. Component Types – Props, Children, Return Types

Basic Component Typing:

Code
// src/components/Button.tsx

// Props type definition
interface ButtonProps {
  label: string;
  onClick: () => void;
  variant?: 'primary' | 'secondary' | 'danger'; // Optional with default
  disabled?: boolean;
  children?: React.ReactNode;
}

// Component with React.FC (FunctionComponent)
const Button: React.FC<ButtonProps> = ({ 
  label, 
  onClick, 
  variant = 'primary',
  disabled = false,
  children 
}) => {
  return (
    <button
      onClick={onClick}
      disabled={disabled}
      className={`btn btn-${variant}`}
    >
      {label}
      {children}
    </button>
  );
};

export default Button;

Alternative – Without React.FC:

Code
// Many developers prefer this (no implicit children)
interface ButtonProps {
  label: string;
  onClick: () => void;
  variant?: 'primary' | 'secondary';
}

function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
  return (
    <button onClick={onClick} className={`btn btn-${variant}`}>
      {label}
    </button>
  );
}

// Explicit children typing
interface CardProps {
  title: string;
  children: React.ReactNode;
}

function Card({ title, children }: CardProps) {
  return (
    <div className="card">
      <h2>{title}</h2>
      <div className="card-content">{children}</div>
    </div>
  );
}

Component Return Types:

Code
// TypeScript automatically infers return type
function SimpleComponent() {
  return <div>Hello</div>; // Type: JSX.Element
}

// Explicit return type (optional but good practice)
function ExplicitComponent(): JSX.Element {
  return <div>Hello</div>;
}

// Component that returns null
function ConditionalComponent(): JSX.Element | null {
  const isVisible = false;
  return isVisible ? <div>Visible</div> : null;
}

// Fragment component
function FragmentComponent(): React.ReactNode {
  return (
    <>
      <h1>Title</h1>
      <p>Content</p>
    </>
  );
}

PropsWithChildren Utility Type:

Code
import { PropsWithChildren } from 'react';

// Instead of manually adding children
interface LayoutProps {
  title: string;
  children: React.ReactNode;
}

// Using PropsWithChildren
interface LayoutProps {
  title: string;
}
// children automatically included
function Layout({ title, children }: PropsWithChildren<LayoutProps>) {
  return (
    <div>
      <h1>{title}</h1>
      {children}
    </div>
  );
}

5. Hooks Typing – useState, useEffect, useReducer, useContext

useState Typing:

Code
// TypeScript automatically infers
const [count, setCount] = useState(0); // count is number

// Explicit type (when initial value is null/undefined)
const [user, setUser] = useState<User | null>(null); // user can be User or null

// Complex state object
interface FormData {
  name: string;
  email: string;
  age: number;
}

const [form, setForm] = useState<FormData>({
  name: '',
  email: '',
  age: 0,
});

// Array state
const [todos, setTodos] = useState<Todo[]>([]);

useEffect Typing:

Code
useEffect(() => {
  // No return value
  const timer = setTimeout(() => {
    console.log('Timer done');
  }, 1000);
  
  // Cleanup function (return void or function)
  return () => {
    clearTimeout(timer);
  };
}, []); // Empty array dependency

useReducer Typing:

Code
// Define state type
interface CounterState {
  count: number;
  step: number;
}

// Define action types
type CounterAction = 
  | { type: 'INCREMENT' }
  | { type: 'DECREMENT' }
  | { type: 'SET_STEP'; payload: number }
  | { type: 'RESET' };

// Reducer with typed state and action
function counterReducer(state: CounterState, action: CounterAction): CounterState {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + state.step };
    case 'DECREMENT':
      return { ...state, count: state.count - state.step };
    case 'SET_STEP':
      return { ...state, step: action.payload };
    case 'RESET':
      return { ...state, count: 0 };
    default:
      return state;
  }
}

// Use in component
function Counter() {
  const [state, dispatch] = useReducer(counterReducer, { count: 0, step: 1 });
  
  return (
    <div>
      <p>Count: {state.count}</p>
      <p>Step: {state.step}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-</button>
      <button onClick={() => dispatch({ type: 'SET_STEP', payload: 2 })}>
        Set Step 2
      </button>
    </div>
  );
}

useContext Typing:

Code
// src/contexts/ThemeContext.tsx
import { createContext, useContext, useState, ReactNode } from 'react';

// Context type
interface ThemeContextType {
  theme: 'light' | 'dark';
  toggleTheme: () => void;
}

// Create context with initial value (null or default)
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

// Provider component
export function ThemeProvider({ children }: { children: ReactNode }) {
  const [theme, setTheme] = useState<'light' | 'dark'>('light');
  
  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };
  
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

// Custom hook with type guard
export function useTheme() {
  const context = useContext(ThemeContext);
  if (context === undefined) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
}

useRef Typing:

Code
import { useRef } from 'react';

// For DOM elements
function InputFocus() {
  const inputRef = useRef<HTMLInputElement>(null);
  
  const focusInput = () => {
    inputRef.current?.focus(); // Optional chaining for null check
  };
  
  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>Focus Input</button>
    </div>
  );
}

// For mutable values (not DOM)
function Timer() {
  const timerRef = useRef<number | null>(null);
  
  const startTimer = () => {
    timerRef.current = setTimeout(() => {
      console.log('Timer done');
    }, 1000);
  };
  
  const stopTimer = () => {
    if (timerRef.current) {
      clearTimeout(timerRef.current);
      timerRef.current = null;
    }
  };
  
  return (
    <div>
      <button onClick={startTimer}>Start</button>
      <button onClick={stopTimer}>Stop</button>
    </div>
  );
}

6. Event Types – onClick, onChange, onSubmit

Mouse Events:

Code
import { MouseEvent } from 'react';

function Button() {
  // Click event
  const handleClick = (event: MouseEvent<HTMLButtonElement>) => {
    console.log('Button clicked at:', event.clientX, event.clientY);
  };
  
  // Right click
  const handleContextMenu = (event: MouseEvent<HTMLDivElement>) => {
    event.preventDefault();
    console.log('Right clicked!');
  };
  
  return (
    <div onContextMenu={handleContextMenu}>
      <button onClick={handleClick}>Click Me</button>
    </div>
  );
}

Input Events:

Code
import { ChangeEvent, KeyboardEvent } from 'react';

function SearchInput() {
  // Change event
  const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
    console.log('Value:', event.target.value);
  };
  
  // Key press event
  const handleKeyPress = (event: KeyboardEvent<HTMLInputElement>) => {
    if (event.key === 'Enter') {
      console.log('Search submitted:', event.currentTarget.value);
    }
  };
  
  return (
    <input
      type="text"
      onChange={handleChange}
      onKeyPress={handleKeyPress}
      placeholder="Search..."
    />
  );
}

Form Events:

Code
import { FormEvent, useState } from 'react';

interface LoginForm {
  email: string;
  password: string;
}

function LoginForm() {
  const [formData, setFormData] = useState<LoginForm>({
    email: '',
    password: '',
  });
  
  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    console.log('Form submitted:', formData);
  };
  
  const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
    const { name, value } = event.target;
    setFormData(prev => ({ ...prev, [name]: value }));
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        name="email"
        value={formData.email}
        onChange={handleInputChange}
      />
      <input
        type="password"
        name="password"
        value={formData.password}
        onChange={handleInputChange}
      />
      <button type="submit">Login</button>
    </form>
  );
}

Common Event Types:

EventTypeElement
ClickMouseEvent<HTMLButtonElement>button, div, span
ChangeChangeEvent<HTMLInputElement>input, select, textarea
SubmitFormEvent<HTMLFormElement>form
KeyPressKeyboardEvent<HTMLInputElement>input, textarea
FocusFocusEvent<HTMLInputElement>input, button

7. Forms with TypeScript – Controlled Components

Complete Form Example:

Code
// src/types/form.ts
export interface RegistrationForm {
  username: string;
  email: string;
  password: string;
  confirmPassword: string;
  age: number;
  gender: 'male' | 'female' | 'other';
  terms: boolean;
}

export interface FormErrors {
  username?: string;
  email?: string;
  password?: string;
  confirmPassword?: string;
  age?: string;
  terms?: string;
}

// src/components/RegistrationForm.tsx
import { useState, ChangeEvent, FormEvent } from 'react';
import { RegistrationForm, FormErrors } from '../types/form';

function RegistrationForm() {
  const [formData, setFormData] = useState<RegistrationForm>({
    username: '',
    email: '',
    password: '',
    confirmPassword: '',
    age: 0,
    gender: 'male',
    terms: false,
  });
  
  const [errors, setErrors] = useState<FormErrors>({});
  
  const validateField = (name: string, value: any): string | undefined => {
    switch (name) {
      case 'username':
        if (!value) return 'Username is required';
        if (value.length < 3) return 'Username must be at least 3 characters';
        return undefined;
      case 'email':
        if (!value) return 'Email is required';
        if (!/\S+@\S+\.\S+/.test(value)) return 'Email is invalid';
        return undefined;
      case 'password':
        if (!value) return 'Password is required';
        if (value.length < 6) return 'Password must be at least 6 characters';
        return undefined;
      case 'confirmPassword':
        if (value !== formData.password) return 'Passwords do not match';
        return undefined;
      case 'age':
        if (value < 18) return 'You must be 18 or older';
        return undefined;
      case 'terms':
        if (!value) return 'You must accept terms';
        return undefined;
      default:
        return undefined;
    }
  };
  
  const handleChange = (event: ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
    const { name, value, type } = event.target;
    const checked = (event.target as HTMLInputElement).checked;
    
    const newValue = type === 'checkbox' ? checked : 
                     type === 'number' ? parseInt(value) : value;
    
    setFormData(prev => ({ ...prev, [name]: newValue }));
    
    // Validate field on change
    const error = validateField(name, newValue);
    setErrors(prev => ({ ...prev, [name]: error }));
  };
  
  const handleSubmit = (event: FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    
    // Validate all fields
    const newErrors: FormErrors = {};
    Object.keys(formData).forEach(key => {
      const error = validateField(key, formData[key as keyof RegistrationForm]);
      if (error) newErrors[key as keyof FormErrors] = error;
    });
    
    if (Object.keys(newErrors).length > 0) {
      setErrors(newErrors);
      return;
    }
    
    console.log('Form submitted:', formData);
    alert('Registration successful!');
  };
  
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Username:</label>
        <input
          type="text"
          name="username"
          value={formData.username}
          onChange={handleChange}
        />
        {errors.username && <span className="error">{errors.username}</span>}
      </div>
      
      <div>
        <label>Email:</label>
        <input
          type="email"
          name="email"
          value={formData.email}
          onChange={handleChange}
        />
        {errors.email && <span className="error">{errors.email}</span>}
      </div>
      
      <div>
        <label>Password:</label>
        <input
          type="password"
          name="password"
          value={formData.password}
          onChange={handleChange}
        />
        {errors.password && <span className="error">{errors.password}</span>}
      </div>
      
      <div>
        <label>Confirm Password:</label>
        <input
          type="password"
          name="confirmPassword"
          value={formData.confirmPassword}
          onChange={handleChange}
        />
        {errors.confirmPassword && <span className="error">{errors.confirmPassword}</span>}
      </div>
      
      <div>
        <label>Age:</label>
        <input
          type="number"
          name="age"
          value={formData.age}
          onChange={handleChange}
        />
        {errors.age && <span className="error">{errors.age}</span>}
      </div>
      
      <div>
        <label>Gender:</label>
        <select name="gender" value={formData.gender} onChange={handleChange}>
          <option value="male">Male</option>
          <option value="female">Female</option>
          <option value="other">Other</option>
        </select>
      </div>
      
      <div>
        <label>
          <input
            type="checkbox"
            name="terms"
            checked={formData.terms}
            onChange={handleChange}
          />
          Accept Terms & Conditions
        </label>
        {errors.terms && <span className="error">{errors.terms}</span>}
      </div>
      
      <button type="submit">Register</button>
    </form>
  );
}

8. API Integration – Axios + TypeScript

Type Definitions for API:

Code
// src/types/api.ts
export interface User {
  id: number;
  name: string;
  email: string;
  phone: string;
  website: string;
}

export interface Post {
  id: number;
  userId: number;
  title: string;
  body: string;
}

export interface ApiResponse<T> {
  data: T;
  status: number;
  message?: string;
}

// src/services/api.ts
import axios, { AxiosInstance, AxiosResponse, AxiosError } from 'axios';
import { User, Post, ApiResponse } from '../types/api';

class ApiService {
  private api: AxiosInstance;
  
  constructor() {
    this.api = axios.create({
      baseURL: 'https://jsonplaceholder.typicode.com',
      timeout: 10000,
      headers: {
        'Content-Type': 'application/json',
      },
    });
    
    // Request interceptor
    this.api.interceptors.request.use(
      (config) => {
        const token = localStorage.getItem('token');
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },
      (error: AxiosError) => {
        return Promise.reject(error);
      }
    );
    
    // Response interceptor
    this.api.interceptors.response.use(
      (response: AxiosResponse) => response,
      (error: AxiosError) => {
        if (error.response?.status === 401) {
          localStorage.removeItem('token');
          window.location.href = '/login';
        }
        return Promise.reject(error);
      }
    );
  }
  
  async getUsers(): Promise<User[]> {
    const response = await this.api.get<User[]>('/users');
    return response.data;
  }
  
  async getUserById(id: number): Promise<User> {
    const response = await this.api.get<User>(`/users/${id}`);
    return response.data;
  }
  
  async createPost(post: Omit<Post, 'id'>): Promise<Post> {
    const response = await this.api.post<Post>('/posts', post);
    return response.data;
  }
  
  async updatePost(id: number, post: Partial<Post>): Promise<Post> {
    const response = await this.api.put<Post>(`/posts/${id}`, post);
    return response.data;
  }
  
  async deletePost(id: number): Promise<void> {
    await this.api.delete(`/posts/${id}`);
  }
}

export const apiService = new ApiService();

Using API in Component:

Code
// src/components/UserList.tsx
import { useState, useEffect } from 'react';
import { apiService } from '../services/api';
import { User } from '../types/api';

function UserList() {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<string | null>(null);
  
  useEffect(() => {
    const fetchUsers = async () => {
      try {
        setLoading(true);
        const data = await apiService.getUsers();
        setUsers(data);
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Failed to fetch users');
      } finally {
        setLoading(false);
      }
    };
    
    fetchUsers();
  }, []);
  
  if (loading) return <div className="loader">Loading users...</div>;
  if (error) return <div className="error">Error: {error}</div>;
  
  return (
    <div className="user-list">
      <h2>Users ({users.length})</h2>
      <ul>
        {users.map(user => (
          <li key={user.id}>
            <strong>{user.name}</strong>
            <br />
            <small>{user.email}</small>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default UserList;

9. Context API with TypeScript

Complete Context Example:

Code
// src/contexts/AuthContext.tsx
import { createContext, useContext, useState, ReactNode } from 'react';

// Types
interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

interface AuthContextType {
  user: User | null;
  isAuthenticated: boolean;
  loading: boolean;
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
}

// Create context
const AuthContext = createContext<AuthContextType | undefined>(undefined);

// Provider props
interface AuthProviderProps {
  children: ReactNode;
}

// Provider component
export function AuthProvider({ children }: AuthProviderProps) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState<boolean>(false);
  
  const login = async (email: string, password: string): Promise<void> => {
    setLoading(true);
    try {
      // API call
      const response = await fetch('/api/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password }),
      });
      
      if (!response.ok) throw new Error('Login failed');
      
      const userData: User = await response.json();
      setUser(userData);
      localStorage.setItem('token', 'dummy-token');
    } finally {
      setLoading(false);
    }
  };
  
  const logout = () => {
    setUser(null);
    localStorage.removeItem('token');
  };
  
  const value: AuthContextType = {
    user,
    isAuthenticated: !!user,
    loading,
    login,
    logout,
  };
  
  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  );
}

// Custom hook
export function useAuth(): AuthContextType {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error('useAuth must be used within AuthProvider');
  }
  return context;
}

Using Auth Context:

Code
// src/components/Profile.tsx
import { useAuth } from '../contexts/AuthContext';

function Profile() {
  const { user, logout } = useAuth();
  
  if (!user) {
    return <div>Please login</div>;
  }
  
  return (
    <div>
      <h2>Welcome, {user.name}!</h2>
      <p>Email: {user.email}</p>
      <p>Role: {user.role}</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

10. React Utility Types – ComponentProps, PropsWithChildren

ComponentProps – Extract Props Type:

Code
// src/components/Button.tsx
interface ButtonProps {
  label: string;
  onClick: () => void;
  variant: 'primary' | 'secondary';
}

export function Button({ label, onClick, variant }: ButtonProps) {
  return (
    <button onClick={onClick} className={`btn btn-${variant}`}>
      {label}
    </button>
  );
}

// Another component that wraps Button
import { ComponentProps } from 'react';
import { Button } from './Button';

// Extract Button's props type
type ButtonPropsFromComponent = ComponentProps<typeof Button>;

const defaultButtonProps: ButtonPropsFromComponent = {
  label: 'Click',
  onClick: () => console.log('clicked'),
  variant: 'primary',
};

function ButtonWrapper(props: ButtonPropsFromComponent) {
  return <Button {...props} />;
}

PropsWithChildren:

Code
import { PropsWithChildren } from 'react';

// Without PropsWithChildren
interface CardProps {
  title: string;
  children: React.ReactNode;
}

// With PropsWithChildren (children automatically included)
interface CardProps {
  title: string;
}

function Card({ title, children }: PropsWithChildren<CardProps>) {
  return (
    <div className="card">
      <h2>{title}</h2>
      <div className="card-content">{children}</div>
    </div>
  );
}

Omit, Pick, Partial with Props:

Code
interface UserCardProps {
  id: number;
  name: string;
  email: string;
  age: number;
  phone: string;
  address: string;
}

// Create type with only id and name
type UserCardBasic = Pick<UserCardProps, 'id' | 'name'>;

// Create type without email and phone
type UserCardWithoutContact = Omit<UserCardProps, 'email' | 'phone'>;

// Make all props optional
type UserCardPartial = Partial<UserCardProps>;

11. Real-world Job-Ready Project Structure

Complete Project Structure:

Code
// src/types/index.ts
export * from './user';
export * from './product';
export * from './api';

// src/types/user.ts
export interface User {
  id: number;
  name: string;
  email: string;
  avatar?: string;
  role: 'admin' | 'user' | 'guest';
  createdAt: Date;
}

// src/types/product.ts
export interface Product {
  id: number;
  name: string;
  price: number;
  category: string;
  inStock: boolean;
}

// src/services/api/client.ts
import axios, { AxiosInstance } from 'axios';

class HttpClient {
  private instance: AxiosInstance;
  
  constructor(baseURL: string) {
    this.instance = axios.create({
      baseURL,
      timeout: 10000,
    });
    
    this.setupInterceptors();
  }
  
  private setupInterceptors() {
    this.instance.interceptors.request.use((config) => {
      const token = localStorage.getItem('token');
      if (token) {
        config.headers.Authorization = `Bearer ${token}`;
      }
      return config;
    });
  }
  
  get<T>(url: string) {
    return this.instance.get<T>(url);
  }
  
  post<T>(url: string, data: any) {
    return this.instance.post<T>(url, data);
  }
  
  put<T>(url: string, data: any) {
    return this.instance.put<T>(url, data);
  }
  
  delete<T>(url: string) {
    return this.instance.delete<T>(url);
  }
}

export const httpClient = new HttpClient(import.meta.env.VITE_API_URL);

Custom Hook with TypeScript:

Code
// src/hooks/useFetch.ts
import { useState, useEffect, useCallback } from 'react';
import { httpClient } from '../services/api/client';

interface UseFetchOptions {
  immediate?: boolean;
  onSuccess?: (data: any) => void;
  onError?: (error: Error) => void;
}

function useFetch<T = any>(url: string, options: UseFetchOptions = {}) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState<boolean>(false);
  const [error, setError] = useState<Error | null>(null);
  
  const fetchData = useCallback(async () => {
    try {
      setLoading(true);
      setError(null);
      const response = await httpClient.get<T>(url);
      setData(response.data);
      options.onSuccess?.(response.data);
    } catch (err) {
      const error = err instanceof Error ? err : new Error('Unknown error');
      setError(error);
      options.onError?.(error);
    } finally {
      setLoading(false);
    }
  }, [url]);
  
  useEffect(() => {
    if (options.immediate !== false) {
      fetchData();
    }
  }, [fetchData]);
  
  return { data, loading, error, refetch: fetchData };
}

export default useFetch;

Component with TypeScript:

Code
// src/pages/ProductList.tsx
import { useState } from 'react';
import useFetch from '../hooks/useFetch';
import { Product } from '../types/product';

function ProductList() {
  const [category, setCategory] = useState<string>('all');
  const { data: products, loading, error } = useFetch<Product[]>('/api/products');
  
  const filteredProducts = products?.filter(
    product => category === 'all' || product.category === category
  );
  
  if (loading) return <ProductSkeleton />;
  if (error) return <ErrorMessage error={error} />;
  
  return (
    <div>
      <CategoryFilter value={category} onChange={setCategory} />
      <div className="products-grid">
        {filteredProducts?.map(product => (
          <ProductCard key={product.id} product={product} />
        ))}
      </div>
    </div>
  );
}

// ProductCard with typed props
interface ProductCardProps {
  product: Product;
}

function ProductCard({ product }: ProductCardProps) {
  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <span className={product.inStock ? 'in-stock' : 'out-of-stock'}>
        {product.inStock ? 'In Stock' : 'Out of Stock'}
      </span>
    </div>
  );
}

// CategoryFilter with typed props
interface CategoryFilterProps {
  value: string;
  onChange: (value: string) => void;
}

function CategoryFilter({ value, onChange }: CategoryFilterProps) {
  const categories = ['all', 'electronics', 'clothing', 'books'];
  
  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      {categories.map(cat => (
        <option key={cat} value={cat}>
          {cat.toUpperCase()}
        </option>
      ))}
    </select>
  );
}

12. Common Mistakes + Solutions

Mistake 1: Using any type

Code
// ❌ Avoid any – defeats TypeScript purpose
function handleData(data: any) {
  console.log(data.name); // No type safety
}

// ✅ Use proper type or unknown
function handleData(data: unknown) {
  if (typeof data === 'object' && data !== null && 'name' in data) {
    console.log(data.name);
  }
}

// ✅ Better – proper interface
interface Data {
  name: string;
  age: number;
}
function handleData(data: Data) {
  console.log(data.name);
}

Mistake 2: Not handling null/undefined

Code
// ❌ No null check
function UserProfile({ user }: { user: User }) {
  return <div>{user.name}</div>; // Crash if user is null
}

// ✅ Handle nullable
function UserProfile({ user }: { user: User | null }) {
  if (!user) return <div>No user data</div>;
  return <div>{user.name}</div>;
}

Mistake 3: Missing event types

Code
// ❌ Using any for events
function handleClick(e: any) {
  console.log(e.target.value);
}

// ✅ Proper event type
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
  console.log(e.currentTarget.value);
}

Mistake 4: Not typing useState initial value

Code
// ❌ TypeScript can't infer
const [user, setUser] = useState(null); // user is null always

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

13. Quick Cheat Sheet

ConceptSyntax
Component Propsinterface Props { name: string }
Childrenchildren: React.ReactNode
useStateconst [state, setState] = useState<Type>(initial)
useEffectuseEffect(() => {}, [deps])
useRefconst ref = useRef<HTMLDivElement>(null)
Event(e: React.ChangeEvent<HTMLInputElement>) => void
API Responseconst { data } = await axios.get<User[]>('/users')
ContextcreateContext<Type | undefined>(undefined)
React.FCconst Component: React.FC<Props> = ({ prop }) => {}
ComponentPropstype Props = ComponentProps<typeof Button>

14. FAQ

Q1: TypeScript with React Hindi में सबसे important benefit kya hai?
Type safety – runtime errors 70% kam ho jaate hain aur development experience better hota hai.

Q2: Kya sab components mein types likhna zaroori hai?
Haan – better safe than sorry. TypeScript inference use karo, lekin complex props mein explicit types likho.

Q3: React.FC use karein ya nahi?
Personal preference। React.FC implicitly children include karta hai। Many developers prefer explicit typing without React.FC।

Q4: API responses ka type kaise guarantee karein?
TypeScript compile-time guarantee karta hai – runtime mein API wrong data bhej sakti hai। Zod jaise validation library use karo runtime ke liye।

Q5: any type kab use karein?
Almost never। unknown better hai। any sirf migration ke time ya third-party library issue ho tab।

Q6: TypeScript se bundle size badhti hai?
Nahi – TypeScript compile time hat jaata hai। Runtime par sirf JavaScript rehti hai।

Q7: TypeScript + React seekhne mein kitna time lagta hai?
TypeScript basics – 2-3 days। React + TypeScript together – 1-2 weeks।

Q8: Vite vs CRA – TypeScript ke liye kya better hai?
Vite – faster, modern, recommended for 2026। CRA is slower and deprecated।

Q9: Generic components kaise banayein?
function List<T>({ items, renderItem }: ListProps<T>) { }

Q10: TypeScript strict mode kyun use karein?
Strict mode better type checking karta hai – strict: true in tsconfig.json।


15. Conclusion

बहुत बढ़िया दोस्तों! आज हमने TypeScript with React Hindi को पूरी detail में समझा।

Quick Recap:

ConceptKey Takeaway
SetupVite + TypeScript template
Component TypesProps, children, return types
HooksuseState, useEffect, useReducer typing
EventsMouseEvent, ChangeEvent, FormEvent
APIAxios + TypeScript interfaces
ContextType-safe context with custom hooks
Utility TypesComponentProps, PropsWithChildren

Mera personal experience:

जब मैंने पहली बार TypeScript + React use kiya, toh mujhe lagta tha “JavaScript enough hai”। But ek baar production bug aaya – API ne string bhej diya jahan number expected tha – app crash ho gayi। Tabse TypeScript use karta hoon, aisa bug kabhi nahi aaya।

Tum bhi ye steps follow karo:

  1. ✅ Vite + TypeScript project create karo
  2. ✅ Components ko type karo
  3. ✅ Hooks sahi se type karo
  4. ✅ API responses ke liye interfaces banao
  5. ✅ Strict mode enable rakho

अब तुम्हारी बारी है!

नीचे comment में बताओ:

  1. तुम TypeScript use karoge React ke saath ya nahi? क्यों?
  2. तुम्हें कौन sa TypeScript feature sabse useful laga?
  3. अगला topic क्या चाहिए? (Next.js? Tailwind CSS? React Native?)

The Easy Master पर बने रहो। Happy Typing! ⚛️📘


Resources

Additional Resources

TheEasyMaster

Author at The Easy Master.

Previous
React Performance Optimization – App Ko Fast कैसे बनाएं 2026
Next
React 19 New Features – AI Integration with React (2026)

Related posts

Leave a Reply

Your email address will not be published. Required fields are marked *