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(this.name);
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(super.name, this.salary);
final int salary;
}
This works with named arguments too:
class Person {
Person({required this.name});
final String name;
}
// New way: Dart 2.17 and above
class Employee extends Person {
Employee({required super.name, 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!