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
EasyLet'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 aProductclass with:- A
String nameproperty - A
String categoryproperty - A
double priceproperty - A constructor that initializes all three properties
- A
main.dart: Import your product file and create anInventoryclass that uses type-safe collections:- A
List<Product>calledproductsto store all products in order - A
Set<String>calledcategoriesto track unique category names - A
Map<String, double>calledpriceByNameto quickly look up prices by product name
- An
addProduct(Product p)method that adds the product to all three collections appropriately - A
printSummary()method that prints the inventory summary
main()function:- Create an
Inventoryinstance - Add these products in order:
'Laptop'in category'Electronics'priced at999.99'Headphones'in category'Electronics'priced at149.99'Coffee Maker'in category'Kitchen'priced at79.99'Notebook'in category'Office'priced at4.99
- Call
printSummary()
- A
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()
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesLibraries & ImportsIntroduction to OOPClasses vs ObjectsThe this KeywordMethodsInstance VariablesConstructor BasicsRecap - Simple Calculator4Null Safety
Intro to Null SafetyNullable vs Non-NullableThe ? and ! OperatorsLate Keyword & Null SafetyNull-Aware OperatorsNull Safety in ClassesRecap - User Profile System7Abstract Classes & Interfaces
Abstract ClassesAbstract MethodsInterfaces in DartImplicit InterfacesImplementing vs ExtendingMultiple InterfacesRecap - Shape Calculator10Collections & Generics
List, Set, Map OverviewType-Safe CollectionsGeneric ClassesGeneric MethodsGeneric ConstraintsIterable & IteratorRecap - Generic Storage13Advanced OOP Concepts
Composition vs InheritanceExtension MethodsCallable ClassesSealed Classes (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums with Methods16Project: Library Management
Project OverviewBook and User Classes2Constructors in Dart
Default ConstructorNamed ConstructorsInitializer ListsConstant ConstructorsFactory ConstructorsRedirecting ConstructorsRecap - Shape Builder5Encapsulation
Public vs Private MembersThe _ Prefix ConventionLibrary-Level PrivacyGetters & Setters DepthInformation HidingRecap - Student Records8Mixins
Introduction to MixinsCreating MixinsUsing Multiple Mixinson Keyword in MixinsMixin vs InheritanceMixin vs InterfaceRecap - Animal System11Special Methods
toString() OverridehashCode & == OverrideComparable Interfacecall() MethodnoSuchMethod OverrideRecap - Custom Collection14Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy Pattern3Class Properties
Instance vs Static MembersFinal & Const FieldsLate VariablesStatic Methods & FieldsGetters and SettersRecap - Bank Account Manager6Inheritance
Basic InheritanceThe super KeywordMethod OverridingThe @override AnnotationThe final Class KeywordConstructors & InheritanceRecap - Employee Hierarchy9Polymorphism
Polymorphism BasicsPolymorphism via InterfacesRuntime Type CheckingThe is & as OperatorsCovariant KeywordRecap - Payment Processor