How to Use Super Initializers in Dart 2.17

Starting from Dart 2.17, you can pass constructor parameters to the superclass with a new shorthand syntax.

For reference, here's how the old syntax used to look like:

class Person { Person(; final String name; } // Old way: before Dart 2.17 class Employee extends Person { Employee(String name, this.salary) : super(name); final int salary; }

In other words, you had to call super explicitly in order to pass arguments to the parent constructor.

Since Dart 2.17, you can do this:

// New way: Dart 2.17 and above class Employee extends Person { Employee(, this.salary); final int salary; }

This works with named arguments too:

class Person { Person({required}); final String name; } // New way: Dart 2.17 and above class Employee extends Person { Employee({required, required this.salary}); final int salary; }

Usage in widget constructors

Super initializers help us reduce the size of the constructor in many widget classes.

For example, the CircularProgressIndicator widget in the Flutter SDK can be upgraded from this:

class CircularProgressIndicator extends ProgressIndicator { const CircularProgressIndicator({ Key? key, double? value, Color? backgroundColor, Color? color, Animation<Color?>? valueColor, String? semanticsLabel, String? semanticsValue, }) : super( key: key, value: value, backgroundColor: backgroundColor, color: color, valueColor: valueColor, semanticsLabel: semanticsLabel, semanticsValue: semanticsValue, ); }

To this:

class CircularProgressIndicator extends ProgressIndicator { const CircularProgressIndicator({ super.key, super.value, super.backgroundColor, super.color, super.valueColor, super.semanticsLabel, super.semanticsValue, }); }

In practice, the most common use case is to make it easier to specify the widget key:

class OrderStatusLabel extends StatelessWidget { // before (Dart 2.16 and below) const OrderStatusLabel({Key? key, required this.order}) : super(key: key); // after (Dart 2.17 and above) const OrderStatusLabel({super.key, required this.order}); final Order order; ... }

Automatic migration with dart fix

If we have a lot of pre-exisiting code, updating all the constructors by hand would be tedious.

But since the Dart team loves us, we can use the dart fix command to upgrade all our code to the new syntax. 💙

To do this, we need to add this additional linter rule to our analysis_options.yaml:

linter: rules: - use_super_parameters

And then we can use the --dry-run flag to preview the proposed changes:

dart fix --dry-run

And once we're happy, we can use the --apply flag to upgrade our code:

dart fix --apply

It really couldn't be any easier! So go ahead and upgrade your code. 🚀

Happy coding!


Want More?

Invest in yourself with my high-quality Flutter courses.

Flutter Foundations Course

Flutter Foundations Course

Learn about State Management, App Architecture, Navigation, Testing, and much more by building a Flutter eCommerce app on iOS, Android, and web.

Flutter & Firebase Masterclass

Flutter & Firebase Masterclass

Learn about Firebase Auth, Cloud Firestore, Cloud Functions, Stripe payments, and much more by building a full-stack eCommerce app with Flutter & Firebase.

The Complete Dart Developer Guide

The Complete Dart Developer Guide

Learn Dart Programming in depth. Includes: basic to advanced topics, exercises, and projects. Fully updated to Dart 2.15.

Flutter Animations Masterclass

Flutter Animations Masterclass

Master Flutter animations and build a completely custom habit tracking application.