Back to Blog
Lesson 10 of the TypeScript: Typing JavaScript with Confidence course
TypeScriptJuly 28, 20264 min read

Working with Arrays of Objects in TypeScript

Master arrays of objects in TypeScript. Learn to type collections of interfaces, iterate safely, and keep your task data structures predictable and error-free.

TypeScriptArraysCollectionsTypingObjects
Colorful overhead photo showcasing assorted paint cans with brushes on a grid pattern background.

Previously in this course, we explored Defining Object Shapes with Interfaces and Typing Function Parameters in TypeScript. Now that you can describe a single task, it's time to manage groups of them by working with arrays of objects.

In real-world applications, you rarely deal with single items in isolation. APIs usually return lists, and your UI components need to render collections. Typing these collections correctly is the difference between a resilient application and one that crashes when an array is empty or malformed.

Defining Arrays of Interfaces

In JavaScript, an array is a flexible container. In TypeScript, we want to enforce that every item inside that container conforms to a specific shape. If we have a Task interface, we define an array of these objects by appending [] to the interface name.

TYPESCRIPT
interface Task {
  id: number;
  title: string;
  isCompleted: boolean;
}

// Defining a collection of tasks
const tasks: Task[] = [
  { id: 1, title: "Learn TypeScript Arrays", isCompleted: false },
  { id: 2, title: "Build the API client", isCompleted: true }
];

By using Task[], TypeScript ensures that any object you push into this array—or any item you access from it—must satisfy the Task interface. If you try to add an object missing the id property, the compiler will stop you immediately.

Iterating Over Typed Arrays

Detailed view of programming code in a dark theme on a computer screen.

Once you have a typed array, you need to iterate over it. Because the compiler knows the structure of each element, your IDE's autocomplete will suggest properties like .title or .isCompleted inside your loops.

When using methods like .map(), .filter(), or .forEach(), TypeScript automatically infers the type of the current element.

TYPESCRIPT
// Iterating safely
tasks.forEach((task) => {
  // TypeScript knows CE9178">'task' is of type Task
  console.log(CE9178">`Task: ${task.title.toUpperCase()}`);
});

This is significantly safer than standard JavaScript, where you might accidentally misspell a property name or assume an object exists when it doesn't.

Accessing Array Elements Safely

A common source of runtime bugs is accessing an array index that doesn't exist. If you try to access tasks[5] in an array of only two items, JavaScript returns undefined. TypeScript, depending on your configuration, might warn you, but you should handle this explicitly.

To access elements safely, always verify the existence of the element or use optional chaining if you aren't certain the index is populated.

TYPESCRIPT
const firstTask = tasks[0]; // Type is Task

// Accessing an potentially empty index
const eleventhTask = tasks[10]; 

// Safe access: TypeScript forces you to consider the CE9178">'undefined' case
if (eleventhTask) {
  console.log(eleventhTask.title);
} else {
  console.log("Task not found.");
}

Hands-on Exercise: Building the Task List

In our ongoing task API client project, let's implement a function that processes a list of tasks.

  1. Create an interface named Task with id, title, and isCompleted.
  2. Define an array named myTasks initialized with at least two Task objects.
  3. Write a function called printTaskTitles that accepts Task[] as a parameter and logs each title.
TYPESCRIPT
interface Task {
  id: number;
  title: string;
  isCompleted: boolean;
}

const myTasks: Task[] = [
  { id: 1, title: "Setup Project", isCompleted: true },
  { id: 2, title: "Type the Arrays", isCompleted: false }
];

function printTaskTitles(tasks: Task[]): void {
  tasks.forEach(t => console.log(t.title));
}

printTaskTitles(myTasks);

Common Pitfalls

  • Forgetting the []: A common mistake is typing a variable as Task instead of Task[]. If you try to call .map() on a single object, your code will crash at runtime.
  • The any[] trap: Avoid using any[]. It defeats the purpose of TypeScript by allowing any data type to enter your collection. Always strive for specific interfaces.
  • Assuming length: Never assume an API returns an array. If your data comes from an external source, it might be null or undefined. Always check if your variable is an array before iterating.

FAQ

Q: Can I use Array<Task> instead of Task[]? A: Yes. Both are functionally equivalent. Task[] is more concise and commonly preferred by the community, but Array<Task> is perfectly valid.

Q: How do I handle arrays that might be empty? A: TypeScript doesn't treat empty arrays differently; they are still of type Task[]. Your code should simply check for the existence of elements inside the array before rendering them, usually through your framework's conditional rendering or a standard if check.

Recap

Wooden Scrabble tiles spelling 'RECAP' on a brown textured background. Text concept image.

Working with collections requires a clear contract. By using Task[] (or Array<Task>), you provide TypeScript the metadata needed to prevent property access errors during iteration. Always prioritize explicit typing over any to keep your task client maintainable.

Up next: We will dive into Understanding Void and Undefined to clarify how to handle functions that don't return values and optional object properties.

Similar Posts