Menu
Coddy logo textTech

Type-Safe Collections

Part of the Object Oriented Programming section of Coddy's Dart journey — lesson 64 of 110.

When you create a collection without specifying a type, Dart infers it from the initial values. But what happens when you need an empty collection, or want to ensure only specific types can be added? That's where type annotations come in.

By adding a type parameter in angle brackets, you create a type-safe collection that only accepts elements of that type:

List<String> names = [];
names.add('Alice');
names.add('Bob');
// names.add(42);  // Error: int can't be added to List<String>

Set<int> numbers = {1, 2, 3};
Map<String, double> prices = {'apple': 1.99, 'banana': 0.99};

This becomes especially powerful with your own classes. You can create collections that only hold specific object types:

class User {
  String name;
  User(this.name);
}

void main() {
  List<User> users = [];
  users.add(User('Alice'));
  users.add(User('Bob'));
  
  for (User user in users) {
    print(user.name);  // Dart knows each item is a User
  }
}

The compiler catches type mismatches before your code runs, and you get full autocomplete support when working with collection elements. This is the foundation of generics, which you'll explore in depth in the upcoming lessons.

challenge icon

Challenge

Easy

Let's build a product inventory system that demonstrates the power of type-safe collections. You'll create a Product class and an Inventory class that uses typed collections to manage products, track categories, and store pricing information.

You'll organize your code into two files:

  • product.dart: Define a Product class with:
    • A String name property
    • A String category property
    • A double price property
    • A constructor that initializes all three properties
  • main.dart: Import your product file and create an Inventory class that uses type-safe collections:
    • A List<Product> called products to store all products in order
    • A Set<String> called categories to track unique category names
    • A Map<String, double> called priceByName to quickly look up prices by product name
    Your Inventory should have:
    • An addProduct(Product p) method that adds the product to all three collections appropriately
    • A printSummary() method that prints the inventory summary
    In your main() function:
    • Create an Inventory instance
    • Add these products in order:
      • 'Laptop' in category 'Electronics' priced at 999.99
      • 'Headphones' in category 'Electronics' priced at 149.99
      • 'Coffee Maker' in category 'Kitchen' priced at 79.99
      • 'Notebook' in category 'Office' priced at 4.99
    • Call printSummary()

The printSummary() method should output the product count, list all unique categories, and show the price lookup map. Notice how each collection type serves a specific purpose: the List maintains product objects in order, the Set automatically handles duplicate categories, and the Map provides quick price lookups.

Expected output:

Total products: 4
Categories: {Electronics, Kitchen, Office}
Price lookup: {Laptop: 999.99, Headphones: 149.99, Coffee Maker: 79.99, Notebook: 4.99}

Cheat sheet

Type annotations allow you to create type-safe collections that only accept elements of a specific type. Add the type in angle brackets:

List<String> names = [];
Set<int> numbers = {1, 2, 3};
Map<String, double> prices = {'apple': 1.99};

Type-safe collections work with custom classes too:

class User {
  String name;
  User(this.name);
}

List<User> users = [];
users.add(User('Alice'));

The compiler catches type mismatches at compile time and provides autocomplete support for collection elements.

Try it yourself

import 'product.dart';

// TODO: Create the Inventory class with:
// - List<Product> products - to store all products in order
// - Set<String> categories - to track unique category names
// - Map<String, double> priceByName - to look up prices by product name

class Inventory {
  // TODO: Declare the three typed collections
  
  // TODO: Create a constructor that initializes the collections
  
  // TODO: Implement addProduct(Product p) method
  // - Add the product to the products list
  // - Add the category to the categories set
  // - Add the name and price to the priceByName map
  
  // TODO: Implement printSummary() method
  // - Print total products count
  // - Print all categories
  // - Print the price lookup map
}

void main() {
  // TODO: Create an Inventory instance
  
  // TODO: Add the following products in order:
  // 1. 'Laptop' in category 'Electronics' priced at 999.99
  // 2. 'Headphones' in category 'Electronics' priced at 149.99
  // 3. 'Coffee Maker' in category 'Kitchen' priced at 79.99
  // 4. 'Notebook' in category 'Office' priced at 4.99
  
  // TODO: Call printSummary()
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming