How do generics work in Dart and why are they useful?
Short Answer
Generics let a class or function be written once and work with any type, while still giving compile-time type safety — List<String> and List<int> are both Lists, but the compiler prevents mixing types into either.
Without generics, a collection would either be locked to one specific type or typed as dynamic/Object (losing compile-time safety, requiring casts everywhere). class Box<T> { T value; Box(this.value); } lets Box<int> and Box<String> share one implementation while the compiler still enforces that a Box<int>'s value is always an int.
Generic bounds (class NumberBox<T extends num> {}) further restrict which types are valid, letting you call methods specific to that bound inside the generic class body.
Code Example
class Repository<T> {
final List<T> _items = [];
void add(T item) => _items.add(item);
List<T> getAll() => List.unmodifiable(_items);
}
final userRepo = Repository<User>();
userRepo.add(User(name: 'Ana')); // type-checked at compile timeCommon Mistakes
- ×Using dynamic instead of a proper generic type parameter, silently losing compile-time type checking.
- ×Not adding a bound (extends) when the generic type needs to support specific operations, then working around it with unsafe casts.