Boost Your Flutter Code Quality with Enums
Ashish Bhakhand
Senior Software Engineer | Crafting Scalable and Maintainable Systems
This article was originally published on Medium
As a developer, you’re no stranger to strings used as identifiers — whether it’s checking user roles, handling states, or defining types in your app. While using strings may seem simple at first, they often lead to common bugs caused by typos or inconsistent values. Thankfully, Dart provides a safer and more robust alternative: enums.
In this article, we’ll dive into how enums can improve your code quality, reduce bugs, and make your code easier to maintain. Plus, we’ll explore enhanced enums, which add even more power to this feature.
What Are Enums?
Enums (short for enumerations) are a special type in Dart that allow you to define a fixed set of related values, giving your code more structure and clarity. Instead of using strings to represent a set of possible values, you use an enum to create a type-safe list of options.
Here’s a simple example of an enum in Dart:
enum UserRole {
admin,
user,
guest,
}
With this, you have clearly defined options for user roles, and you can avoid using arbitrary strings like "admin", "user", and "guest" throughout your codebase.
How Enums Improve Code Quality
Example:
void printUserRole(UserRole role) {
if (role == UserRole.admin) {
print('Welcome, Admin!');
}
}
Here, you’re working with a strict set of values, which means fewer mistakes and more reliable code.
2. Cleaner and More Readable Code Enums help keep your code clean by reducing the need for multiple string or int comparisons scattered throughout your app. You can switch on an enum, making your logic more readable and easier to follow:
Example:
switch (user.role) {
case UserRole.admin:
// Admin-specific logic
break;
case UserRole.user:
// User-specific logic
break;
case UserRole.guest:
// Guest-specific logic
break;
}
This makes your code more expressive and easier to understand at a glance. No more hunting for "user", "admin", or "guest" strings hidden in multiple places.
Real-World Use Case: Managing App States
Enums are also great for managing app states in Flutter. For instance, imagine you’re building a loading screen that has three possible states: loading, success, and error. Instead of relying on strings to represent these states, you can use an enum:
enum LoadingState {
loading,
success,
error,
}
Now you can easily switch between states in a safe, structured way:
领英推荐
Widget build(BuildContext context) {
switch (state) {
case LoadingState.loading:
return CircularProgressIndicator();
case LoadingState.success:
return Text('Loaded successfully!');
case LoadingState.error:
return Text('Failed to load.');
}
}
By using enums to handle app states, you prevent issues like misspelled state names and ensure that your logic only handles the states you’ve explicitly defined.
Enhanced Enums: Adding Extra Power
Enums in Dart aren’t just about basic value comparisons. They can be powerful tools to structure and enrich your code, especially in real-world scenarios where additional context or properties are needed. Let’s say you want to display different types of snack bars in a Flutter app. Using strings or integers to represent the type is error-prone. Enums to the rescue!
Example: SnackBarType Enum
In a Flutter app, we might want to show different types of snack bars for different purposes, like:
Instead of handling these with basic strings or constants, we can create a well-structured enum:
Using Enhanced Enums
Here’s how you can take your enums to the next level:
enum SnackBarType {
info(
icon: Icons.info,
color: Colors.blue,
),
warning(
icon: Icons.warning,
color: Colors.amber,
),
error(
icon: Icons.error,
color: Colors.red,
),
success(
icon: Icons.check_circle,
color: Colors.green,
);
// Constructor to initialize icon and color
const SnackBarType({
required this.icon,
required this.color,
});
// Final properties for icon and color
final IconData icon;
final Color color;
// Helper getter methods for readability
bool get isError => this == error;
bool get isWarning => this == warning;
bool get isInfo => this == info;
bool get isSuccess => this == success;
}
Now, let’s see how this enum can be used in your Flutter app to display snack bars:
/// Function to show a snackbar with a message and type
void showSnackbar({
required BuildContext context,
required SnackBarType type,
required String message,
}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
Icon(type.icon, color: type.color),
const SizedBox(width: 8),
Text(message),
],
),
backgroundColor: type.color.withOpacity(0.8),
),
);
}
/// Example widget to show a snackbar
class SomeWidget extends StatelessWidget {
const SomeWidget({super.key});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: () {
showSnackbar(
context: context,
type: SnackBarType.error,
message: 'An error occurred',
);
},
child: const Text('Show Error Snackbar'),
);
}
}
This approach keeps your code tidy and encapsulates the logic where it belongs: inside the enum.
Benefits of Using Enums
To summarize, here are the key benefits of using enums in your Dart and Flutter code:
Conclusion
Enums in Dart are a simple yet powerful tool to improve your Flutter code quality, reduce bugs, and make your logic more readable and maintainable. Enhanced enums take this concept further by allowing you to attach properties and methods directly to enum values, giving your code more structure and flexibility.
Next time you find yourself reaching for a string to represent a set of options, consider using an enum instead — you’ll thank yourself later!
What’s your favorite use of enums in your projects? Let me know in the comments, and feel free to share what topic you’d like me to cover next!