Dart Typedefs and Tear-Offs
A typedef gives a type a name of its own. A tear-off takes a function, a method, or a constructor as a value without calling it.
A function type with a name
Compare names a function that takes two strings and returns an int. showResult accepts any function with that shape.
typedef Compare = int Function(String, String);
int byLength(String a, String b) {
return a.length - b.length;
}
void showResult(Compare compare, String a, String b) {
print(compare(a, b));
}
void main() {
showResult(byLength, 'dart', 'go');
showResult((a, b) => b.length - a.length, 'dart', 'go');
}An alias for a long type
Scores names a map from names to lists of marks. The loops add every mark through the alias type without writing the long type again.
typedef Scores = Map<String, List<int>>;
void main() {
Scores scores = {
'Ana': [10, 20],
'Bo': [5, 5],
};
var grand = 0;
for (var list in scores.values) {
for (var mark in list) {
grand += mark;
}
}
print(grand);
print(scores.length);
}A method tear-off
words.add is taken as a value and stored in add. Calling add later still adds to the same words list.
void main() {
var words = <String>[];
var add = words.add;
add('red');
add('blue');
print(words);
print(words.length);
}A constructor tear-off
Dog.new stands for the Dog constructor as a value. Calling the stored value builds a new Dog each time.
class Dog {
String name;
Dog(this.name);
}
void main() {
var makeDog = Dog.new;
var rex = makeDog('Rex');
var pip = makeDog('Pip');
print(rex.name);
print(pip.name);
}Example
class Dog {
String name;
Dog(this.name);
}
List<Dog> buildDogs(Dog Function(String) make, List<String> names) {
var dogs = <Dog>[];
for (var name in names) {
dogs.add(make(name));
}
return dogs;
}
void main() {
var dogs = buildDogs(Dog.new, ['Rex', 'Pip', 'Max']);
print(dogs.length);
print(dogs[0].name);
print(dogs[2].name);
}Key points
- A typedef for a function type names the input types and the result type.
- Code can use a typedef name anywhere the full type could be written.
- A typedef can also alias a long non-function type, such as a nested map type.
- An alias is only a name for the same type, not a new separate type.
- A method tear-off stays bound to the object it was taken from.
- A constructor tear-off such as Dog.new stands for the unnamed constructor as a value.
- A tear-off can be stored in a variable and passed into another function.
In this example, the constructor tear-off Dog.new is passed into buildDogs as the make value. The helper calls make once for each name and collects the new Dog values. The prints show the count and the first and last names.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท DartPad
Exercise
What does the line var add = words.add; store in add?