This tutorial shows you how to create and use type aliases, also known as typedef
s in Dart. It also works in Flutter and there's a usage example for Flutter as well.
In Dart, you can create a type alias to refer to a type by using typedef
keyword. This tutorial explains how to create typedefs for function and non-functions and how to use the created typedefs.
Using typedef
for Functions
The typedef
keyword was initially created in Dart 1 to refer to functions. In Dart 1, if you want to use a function as a variable, field, or parameter, you need to create a typedef
first.
To use a type alias, you only need to assign the function signature to a typedef
. After that, you can use the typedef
as a variable, field, or parameter, as shown in the example below.
typedef IntOperation<int> = int Function(int a, int b);
int processTwoInts (IntOperation<int> intOperation, int a, int b) {
return intOperation(a, b);
}
class MyClass {
IntOperation<int> intOperation;
MyClass(this.intOperation);
int doIntOperation(int a, int b) {
return this.intOperation(a, b);
}
}
void main() {
IntOperation<int> sumTwoNumbers = (int a, int b) => a + b;
print(sumTwoNumbers(1, 1));
print(processTwoInts(sumTwoNumbers, 1, 2));
MyClass myClass = MyClass(sumTwoNumbers);
print(myClass.doIntOperation(3, 4));
}
Output:
2
3
7
Below is another example where the function has a generic parameter type.
typedef Compare<T> = bool Function(T a, T b);
bool compareAsc(int a, int b) => a < b;
int compareAsc2(int a, int b) => a - b;
bool doComparison<T>(Compare<T> compare, T a, T b) {
assert(compare is Compare<T>);
return compare(a, b);
}
void main() {
print(compareAsc is Compare<int>);
print(compareAsc2 is Compare<int>);
doComparison(compareAsc, 1, 2);
doComparison(compareAsc2, 1, 2); // The argument can't be assigned
}
Output:
true
false
true
Since Dart 2, you can use function type syntax anywhere. Therefore, it's not necessary to create a typdef
anymore. Flutter also states that inline function type is preferred. That's because people who read the code can see the function type directly. Below is the equivalent of the first example without typedef
.
int processTwoInts (int Function(int a, int b) intOperation, int a, int b) {
return intOperation(a, b);
}
class MyClass {
int Function(int a, int b) intOperation;
MyClass(this.intOperation);
int doIntOperation(int a, int b) {
return this.intOperation(a, b);
}
}
void main() {
int Function(int a, int b) sumTwoNumbers = (int a, int b) => a + b;
print(sumTwoNumbers(1, 1));
print(processTwoInts(sumTwoNumbers, 1, 2));
MyClass myClass = MyClass(sumTwoNumbers);
print(myClass.doIntOperation(3, 4));
}
However, it can be useful to create a typedef
if the function is long and frequently used.
Using typedef
for Non-Functions
Before Dart 2.13, you can only use typedefs for function types. Since Dart 2.13, you can also use typedef
s for creating type aliases that refer to non-functions. The usage is very similar, you only need to assign the type to be referred as a typedef
.
First, your Dart version must be version 2.13 or above. For Flutter, you need to use version 2.2 or above. You also need to update the minimum SDK version in pubspec.yaml
to 2.13.0 and run pub get
(for Dart) or flutter pub get
(for Flutter).
environment:
sdk: '>=2.13.0 <3.0.0'
For example, you need to define a type that stores a list of integer scores. For that purpose, you can create a typedef
whose type is List<int>
. Later, if you want to define a variable for storing a score list, you can use the typedef
as the type. In the example below, we define a typedef
called ScoreList
whose type is List<int>
. As you can see in the code below, using the typedef
gives you the same behavior as using the actual type. You can directly assign a list value and access the methods and properties of List
. If you check the runtimeType
, you'll get List<int>
as the result.
typedef ScoreList = List<int>;
void main() {
ScoreList scores = [60, 80, 70];
scores.add(100);
print('length: ${scores.length}');
print('values: $scores');
print('type: ${scores.runtimeType}');
}
Output:
length: 4
values: [60, 80, 70, 100]
type: List<int>
Not only as a variable, type aliases can also be used as a field, parameter, and return value of a method.
typedef ScoreList = List<int>;
class MyClass {
ScoreList currentScores;
MyClass({required this.currentScores});
set scores(ScoreList currentScores) {
this.currentScores = currentScores;
}
ScoreList getMultipliedScores(int multiplyFactor) {
ScoreList result = [];
currentScores.forEach((element) {
result.add(element * multiplyFactor);
});
return result;
}
}
void main() {
MyClass myClass = MyClass(currentScores: [60, 80, 70]);
myClass.scores = [70, 90];
print(myClass.currentScores);
print(myClass.getMultipliedScores(2));
}
Output:
[70, 90]
[140, 180]
Below is another example. For example, you need a type for storing request body whose keys and value types can be vary for each type. The Map<String, dynamic>
data type is suitable for that case. But instead of using Map<String, dynamic>
every time you need to declare a request body variable, you can create a typedef
for the type.
typedef RequestBody = Map<String, dynamic>;
void main() {
final RequestBody requestBody1 = {
'type': 'PURCHASE',
'itemId': 1,
'amount': 100,
};
final RequestBody requestBody2 = {
'type': 'CANCEL_PURCHASE',
'orderId': '04184432',
};
print(requestBody1);
print(requestBody2);
}
Output:
{type: PURCHASE, itemId: 1, amount: 100}
{type: CANCEL_PURCHASE, orderId: 04184432}
You can also define a type alias that has a generic type parameter. The ValueList
type alias below has a generic type parameter T
. When you define a variable using the type alias, you can pass the generic type to use.
typedef ValueList<T> = List<T>;
void main() {
ValueList<String> values = ['a', 'b', 'c'];
values.add('d');
print('length: ${values.length}');
print('values: $values');
print('type: ${values.runtimeType}');
}
Output:
length: 4
values: [a, b, c, d]
type: List<String>
Usage in Flutter
The code below is an example for Flutter which creates a typedef
for List<Widget>
type.
import 'package:flutter/material.dart';
typedef WidgetList = List<Widget>;
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Woolha.com Flutter Tutorial',
home: TypedefExample(),
debugShowCheckedModeBanner: false,
);
}
}
class TypedefExample extends StatelessWidget {
WidgetList buildWidgets() {
return <Widget>[
const FlutterLogo(size: 60),
const Text('Woolha.com', style: const TextStyle(color: Colors.teal, fontSize: 24)),
];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
),
body: SizedBox(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: buildWidgets(),
),
),
);
}
}
Summary
That's how to create and use typedef
s in Dart / Flutter. You need to assign a type or a function signature to a typedef
. Then, the created typedef
can be used as a variable, field, parameter, or return value of a method.