Generics in Dart
In this lesson, you will learn about Generics in Dart. Generics allow you to write flexible, reusable, and type-safe code.
They are heavily used in collections, APIs, frameworks, and real-world applications.
Why Generics Are Needed
Without generics, Dart code can become unsafe and error-prone. Let’s understand this with a simple example.
List values = [10, "Dart", true];
values.add(3.14);
This list can hold any data type, which makes it dangerous. You may accidentally insert incorrect values.
Type Safety Problem
If you expect only numbers but accidentally store strings, your program may crash at runtime.
Generics solve this problem by enforcing types at compile time.
Using Generics with Collections
Dart collections like List, Set, and Map support generics.
List scores = [85, 90, 78, 92];
scores.add(88);
Now this list can store only integers.
Real-World Example: Student Marks
Let’s store marks of students using generics.
List marks = [72.5, 88.0, 91.25];
double average = (marks[0] + marks[1] + marks[2]) / marks.length;
print(average);
This ensures that only numerical values are processed.
Generics with Map
Maps also support generics for key-value pairs.
Map productStock = {
"Laptop": 25,
"Mobile": 40,
"Tablet": 15
};
Here, keys must be strings and values must be integers.
Creating Generic Classes
You can create your own classes using generics. This makes them reusable for multiple data types.
class Box {
T value;
Box(this.value);
T getValue() {
return value;
}
}
Using a Generic Class
void main() {
Box numberBox = Box(100);
Box textBox = Box("Dataplexa");
print(numberBox.getValue());
print(textBox.getValue());
}
The same class works with different data types safely.
Real-World Use Case: API Response Wrapper
Generics are commonly used when handling API responses.
class ApiResponse {
T data;
bool success;
ApiResponse(this.data, this.success);
}
Using API Response Class
ApiResponse response =
ApiResponse("User created successfully", true);
print(response.data);
print(response.success);
Generic Functions
Functions can also use generics.
T getFirstElement(List items) {
return items[0];
}
Using Generic Function
void main() {
print(getFirstElement([1, 2, 3]));
print(getFirstElement(["Dart", "Flutter", "Web"]));
}
Restricting Generic Types
You can restrict generic types using constraints.
class NumberBox {
T value;
NumberBox(this.value);
T doubleValue() {
return (value + value) as T;
}
}
Now only numeric types are allowed.
Benefits of Generics
- Compile-time type safety
- Reusable and clean code
- Better readability
- Fewer runtime errors
📝 Practice Exercises
Exercise 1
Create a generic class Storage<T> that stores a value.
Exercise 2
Use it with both int and String.
Exercise 3
Create a generic function that returns the last element of a list.
✅ Practice Answers
class Storage {
T value;
Storage(this.value);
T getValue() => value;
}
T getLast(List items) {
return items[items.length - 1];
}
void main() {
Storage s1 = Storage(500);
Storage s2 = Storage("Dart Generics");
print(s1.getValue());
print(s2.getValue());
print(getLast([10, 20, 30]));
}
What’s Next?
In the next lesson, you will learn about Asynchronous Programming in Dart, including how Dart handles tasks that take time to complete.