Thuta Learning
ProjectsProgrammingintermediate

Mini Project: Task Manager - Part 2 (Class & Filtering)

Relax. We'll talk through this in plain words — no textbook voice.

What you'll walk away with

  • Apply Mini Project: Task Manager - Part 2 (Class & Filtering) in a real project
  • Write and run the code yourself
  • Build out an entire project step by step

Let's think about this for a second

In this part, we'll reorganize the code from Part 1 — which used global variables and standalone functions — into a class. Using classes lets us bundle state (the tasks array) and behavior (addTask, listTasks) together in one place, and encapsulate data with private fields. We'll also add a method that uses union types and type narrowing to filter tasks by status. This step will make it clear just how useful a class-based structure is in real-world applications.

Let's build it

Create a TaskManager class with the fields private tasks: Task[] = [] and private nextId: number = 1. Rewrite the addTask() and listTasks() methods from Part 1 inside the class. Add a new method, updateStatus(id: number, status: TaskStatus): boolean, that finds the task with the matching id in the tasks array and updates its status (returning false if it's not found). Also add filterByStatus(status: TaskStatus): Task[], which returns a new array containing only the tasks matching the given status (use Array.filter()). Finally, create a TaskManager instance, add some tasks, update a status, filter, and test the result with console.log.

Sample code

typescript
class TaskManager {
  private tasks: Task[] = [];
  private nextId: number = 1;

  addTask(title: string, priority: Task["priority"]): Task {
    const task: Task = {
      id: this.nextId++,
      title,
      status: TaskStatus.Todo,
      priority,
    };
    this.tasks.push(task);
    return task;
  }

  listTasks(): void {
    this.tasks.forEach((t) =>
      console.log(`#${t.id} [${t.status}] ${t.title} (${t.priority})`)
    );
  }

  updateStatus(id: number, status: TaskStatus): boolean {
    const task = this.tasks.find((t) => t.id === id);
    if (!task) return false;
    task.status = status;
    return true;
  }

  filterByStatus(status: TaskStatus): Task[] {
    return this.tasks.filter((t) => t.status === status);
  }
}

const manager = new TaskManager();
manager.addTask("Learn generics", "high");
manager.addTask("Deploy project", "medium");
manager.updateStatus(1, TaskStatus.InProgress);

console.log("In Progress tasks:");
manager.filterByStatus(TaskStatus.InProgress).forEach((t) =>
  console.log(`- ${t.title}`)
);
You should see
Under the "In Progress tasks:" heading, only the title of the task whose status was updated ("Learn generics") is shown.

5-minute try it yourself

Add a method removeTask(id: number): boolean to the TaskManager class, and implement it so it removes the task with the matching id from the tasks array using filter().

A quick word of caution

Keep in mind that Array.find() returns a reference to the object it finds, so changing a field on it can directly mutate the object inside the original array too — watch out for this side effect.

Easy traps

  • Not expecting a compile error when trying to access something like manager.tasks directly from outside the instance, after marking a class field private
  • Not knowing that filter() returns a brand-new array instead of mutating the original, and forgetting to store the return value in a variable

Now try it yourself

Add a method removeTask(id: number): boolean to the TaskManager class, and implement it so it removes the task with the matching id from the tasks array using filter().

You'll know it worked when: Under the "In Progress tasks:" heading, only the title of the task whose status was updated ("Learn generics") is shown.

Mini Project: Task Manager - Part 2 (Class & Filtering) | Thuta Learning