Skip to main content
Course/Module 9/Topic 3 of 5Advanced

JavaScript TypeScript Integration

Master TypeScript integration, type systems, and how to leverage TypeScript for building robust JavaScript applications

45 minBy Priygop TeamLast updated: Feb 2026

TypeScript Basics

TypeScript is a superset of JavaScript that adds static typing, interfaces, and advanced language features. It helps catch errors early, provides better tooling support, and makes JavaScript code more maintainable.

TypeScript Configuration

Example
// tsconfig.json
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["DOM", "DOM.Iterable", "ESNext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

// Basic TypeScript types
let name: string = 'John Doe';
let age: number = 30;
let isActive: boolean = true;
let hobbies: string[] = ['reading', 'coding'];
let user: { name: string; age: number } = { name: 'John', age: 30 };

// Union types
let status: 'loading' | 'success' | 'error' = 'loading';
let id: string | number = 'abc123';

// Type aliases
type User = {
  id: number;
  name: string;
  email: string;
  isActive: boolean;
};

type UserStatus = 'active' | 'inactive' | 'pending';

// Interfaces
interface Product {
  id: number;
  name: string;
  price: number;
  category: string;
  inStock: boolean;
}

interface ProductWithDiscount extends Product {
  discount: number;
  discountedPrice: number;
}

// Function types
type MathFunction = (a: number, b: number) => number;
type CallbackFunction = (data: any) => void;

const add: MathFunction = (a, b) => a + b;
const multiply: MathFunction = (a, b) => a * b;

// Generic types
function identity<T>(arg: T): T {
  return arg;
}

function createArray<T>(length: number, value: T): T[] {
  return Array(length).fill(value);
}

// Usage
const stringArray = createArray(3, 'hello');
const numberArray = createArray(5, 0);

TypeScript with React

Example
// React component with TypeScript
import React, { useState, useEffect } from 'react';

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

interface UserCardProps {
  user: User;
  onEdit: (user: User) => void;
  onDelete: (id: number) => void;
  isAdmin?: boolean;
}

const UserCard: React.FC<UserCardProps> = ({ 
  user, 
  onEdit, 
  onDelete, 
  isAdmin = false 
}) => {
  const [isEditing, setIsEditing] = useState<boolean>(false);
  const [editedUser, setEditedUser] = useState<User>(user);

  const handleSave = () => {
    onEdit(editedUser);
    setIsEditing(false);
  };

  const handleCancel = () => {
    setEditedUser(user);
    setIsEditing(false);
  };

  return (
    <div className="user-card">
      {isEditing ? (
        <div className="edit-form">
          <input
            type="text"
            value={editedUser.name}
            onChange={(e) => setEditedUser({
              ...editedUser,
              name: e.target.value
            })}
          />
          <input
            type="email"
            value={editedUser.email}
            onChange={(e) => setEditedUser({
              ...editedUser,
              email: e.target.value
            })}
          />
          <button onClick={handleSave}>Save</button>
          <button onClick={handleCancel}>Cancel</button>
        </div>
      ) : (
        <div className="user-info">
          <h3>{user.name}</h3>
          <p>{user.email}</p>
          {user.avatar && (
            <img src={user.avatar} alt={user.name} />
          )}
          <div className="actions">
            <button onClick={() => setIsEditing(true)}>Edit</button>
            {isAdmin && (
              <button onClick={() => onDelete(user.id)}>Delete</button>
            )}
          </div>
        </div>
      )}
    </div>
  );
};

// Custom hooks with TypeScript
interface UseCounterReturn {
  count: number;
  increment: () => void;
  decrement: () => void;
  reset: () => void;
  setCount: (value: number) => void;
}

const useCounter = (initialValue: number = 0): UseCounterReturn => {
  const [count, setCount] = useState<number>(initialValue);

  const increment = () => setCount(prev => prev + 1);
  const decrement = () => setCount(prev => prev - 1);
  const reset = () => setCount(initialValue);

  return {
    count,
    increment,
    decrement,
    reset,
    setCount
  };
};

// API service with TypeScript
interface ApiResponse<T> {
  data: T;
  status: number;
  message: string;
}

interface UserService {
  getUsers(): Promise<ApiResponse<User[]>>;
  getUser(id: number): Promise<ApiResponse<User>>;
  createUser(user: Omit<User, 'id'>): Promise<ApiResponse<User>>;
  updateUser(id: number, user: Partial<User>): Promise<ApiResponse<User>>;
  deleteUser(id: number): Promise<ApiResponse<void>>;
}

class UserApiService implements UserService {
  private baseUrl: string = 'https://api.example.com/users';

  async getUsers(): Promise<ApiResponse<User[]>> {
    const response = await fetch(this.baseUrl);
    const data = await response.json();
    return {
      data,
      status: response.status,
      message: 'Users retrieved successfully'
    };
  }

  async getUser(id: number): Promise<ApiResponse<User>> {
    const response = await fetch(`${this.baseUrl}/${id}`);
    const data = await response.json();
    return {
      data,
      status: response.status,
      message: 'User retrieved successfully'
    };
  }

  async createUser(user: Omit<User, 'id'>): Promise<ApiResponse<User>> {
    const response = await fetch(this.baseUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(user)
    });
    const data = await response.json();
    return {
      data,
      status: response.status,
      message: 'User created successfully'
    };
  }

  async updateUser(id: number, user: Partial<User>): Promise<ApiResponse<User>> {
    const response = await fetch(`${this.baseUrl}/${id}`, {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(user)
    });
    const data = await response.json();
    return {
      data,
      status: response.status,
      message: 'User updated successfully'
    };
  }

  async deleteUser(id: number): Promise<ApiResponse<void>> {
    const response = await fetch(`${this.baseUrl}/${id}`, {
      method: 'DELETE'
    });
    return {
      data: undefined,
      status: response.status,
      message: 'User deleted successfully'
    };
  }
}

Practice Exercise: TypeScript

Example
// Exercise: Build a TypeScript Todo Application
// 1. Define types and interfaces
interface Todo {
  id: number;
  title: string;
  description?: string;
  completed: boolean;
  priority: 'low' | 'medium' | 'high';
  createdAt: Date;
  updatedAt: Date;
}

interface TodoFilters {
  completed?: boolean;
  priority?: Todo['priority'];
  search?: string;
}

interface TodoStats {
  total: number;
  completed: number;
  pending: number;
  byPriority: Record<Todo['priority'], number>;
}

// 2. Create Todo service
class TodoService {
  private todos: Todo[] = [];
  private nextId: number = 1;

  addTodo(todoData: Omit<Todo, 'id' | 'completed' | 'createdAt' | 'updatedAt'>): Todo {
    const todo: Todo = {
      ...todoData,
      id: this.nextId++,
      completed: false,
      createdAt: new Date(),
      updatedAt: new Date()
    };
    
    this.todos.push(todo);
    return todo;
  }

  getTodos(filters?: TodoFilters): Todo[] {
    let filteredTodos = [...this.todos];

    if (filters?.completed !== undefined) {
      filteredTodos = filteredTodos.filter(todo => todo.completed === filters.completed);
    }

    if (filters?.priority) {
      filteredTodos = filteredTodos.filter(todo => todo.priority === filters.priority);
    }

    if (filters?.search) {
      const searchLower = filters.search.toLowerCase();
      filteredTodos = filteredTodos.filter(todo => 
        todo.title.toLowerCase().includes(searchLower) ||
        todo.description?.toLowerCase().includes(searchLower)
      );
    }

    return filteredTodos;
  }

  getTodo(id: number): Todo | undefined {
    return this.todos.find(todo => todo.id === id);
  }

  updateTodo(id: number, updates: Partial<Omit<Todo, 'id' | 'createdAt'>>): Todo | undefined {
    const todoIndex = this.todos.findIndex(todo => todo.id === id);
    
    if (todoIndex === -1) return undefined;

    this.todos[todoIndex] = {
      ...this.todos[todoIndex],
      ...updates,
      updatedAt: new Date()
    };

    return this.todos[todoIndex];
  }

  deleteTodo(id: number): boolean {
    const initialLength = this.todos.length;
    this.todos = this.todos.filter(todo => todo.id !== id);
    return this.todos.length < initialLength;
  }

  toggleTodo(id: number): Todo | undefined {
    const todo = this.getTodo(id);
    if (!todo) return undefined;

    return this.updateTodo(id, { completed: !todo.completed });
  }

  getStats(): TodoStats {
    const total = this.todos.length;
    const completed = this.todos.filter(todo => todo.completed).length;
    const pending = total - completed;

    const byPriority = {
      low: this.todos.filter(todo => todo.priority === 'low').length,
      medium: this.todos.filter(todo => todo.priority === 'medium').length,
      high: this.todos.filter(todo => todo.priority === 'high').length
    };

    return { total, completed, pending, byPriority };
  }
}

// 3. Create React components with TypeScript
import React, { useState, useEffect } from 'react';

interface TodoAppProps {
  service: TodoService;
}

const TodoApp: React.FC<TodoAppProps> = ({ service }) => {
  const [todos, setTodos] = useState<Todo[]>([]);
  const [filters, setFilters] = useState<TodoFilters>({});
  const [stats, setStats] = useState<TodoStats>({
    total: 0,
    completed: 0,
    pending: 0,
    byPriority: { low: 0, medium: 0, high: 0 }
  });

  useEffect(() => {
    updateTodos();
    updateStats();
  }, [filters]);

  const updateTodos = () => {
    setTodos(service.getTodos(filters));
  };

  const updateStats = () => {
    setStats(service.getStats());
  };

  const handleAddTodo = (todoData: Omit<Todo, 'id' | 'completed' | 'createdAt' | 'updatedAt'>) => {
    service.addTodo(todoData);
    updateTodos();
    updateStats();
  };

  const handleToggleTodo = (id: number) => {
    service.toggleTodo(id);
    updateTodos();
    updateStats();
  };

  const handleDeleteTodo = (id: number) => {
    service.deleteTodo(id);
    updateTodos();
    updateStats();
  };

  return (
    <div className="todo-app">
      <TodoForm onAdd={handleAddTodo} />
      <TodoFilters filters={filters} onFiltersChange={setFilters} />
      <TodoList 
        todos={todos}
        onToggle={handleToggleTodo}
        onDelete={handleDeleteTodo}
      />
      <TodoStats stats={stats} />
    </div>
  );
};

// 4. Test the application
const todoService = new TodoService();

// Add some todos
todoService.addTodo({
  title: 'Learn TypeScript',
  description: 'Master TypeScript fundamentals',
  priority: 'high'
});

todoService.addTodo({
  title: 'Build React app',
  description: 'Create a todo application',
  priority: 'medium'
});

todoService.addTodo({
  title: 'Write tests',
  description: 'Add unit and integration tests',
  priority: 'low'
});

// Get todos with filters
const highPriorityTodos = todoService.getTodos({ priority: 'high' });
const completedTodos = todoService.getTodos({ completed: true });

// Get statistics
const stats = todoService.getStats();
console.log('Todo Statistics:', stats);
Chat on WhatsApp
Priygop - Leading Professional Development Platform | Expert Courses & Interview Prep