Dart Tutorial

Dart Lesson 26 of 102 2 min read

typedef in Dart: Naming Function and Other Types

Use typedef in Dart to give long function types and generic types a short, readable name. Includes practical callback examples.

On this page

A typedef gives a type a second name. It does not create a new type. It is a shortcut that makes long types readable and keeps them in one place.

The problem it solves #

Function types get long quickly.

void fetchUser(
  int id,
  void Function(String name, int age) onSuccess,
  void Function(String message) onError,
) {
  if (id > 0) {
    onSuccess('Kiran', 28);
  } else {
    onError('Invalid id');
  }
}

void main() {
  fetchUser(1, (name, age) => print('$name, $age'), print);
}

Naming the function types #

typedef UserCallback = void Function(String name, int age);
typedef ErrorCallback = void Function(String message);

void fetchUser(int id, UserCallback onSuccess, ErrorCallback onError) {
  if (id > 0) {
    onSuccess('Kiran', 28);
  } else {
    onError('Invalid id');
  }
}

void main() {
  fetchUser(1, (name, age) => print('$name, $age'), print);
  fetchUser(-1, (name, age) => print('$name, $age'), print);
}
Kiran, 28
Invalid id

The signature of fetchUser now fits on one line and says what each callback is for.

Aliases for any type #

A typedef is not limited to functions. It can shorten any type, which is useful for nested generics and records.

typedef Json = Map<String, dynamic>;
typedef Point = (double x, double y);
typedef Scores = Map<String, List<int>>;

String describe(Json data) => '${data['name']} (${data['age']})';

double squaredLength(Point p) => p.$1 * p.$1 + p.$2 * p.$2;

void main() {
  Json user = {'name': 'Lila', 'age': 31};
  print(describe(user));

  Point p = (3, 4);
  print(squaredLength(p));

  Scores scores = {'maths': [80, 92]};
  print(scores);
}
Lila (31)
25.0
{maths: [80, 92]}

Generic typedefs #

typedef Predicate<T> = bool Function(T value);
typedef Mapper<A, B> = B Function(A input);

List<T> keep<T>(List<T> items, Predicate<T> test) =>
    [for (final item in items) if (test(item)) item];

void main() {
  print(keep([1, 2, 3, 4], (n) => n.isEven));
  print(keep(['a', 'bb', 'ccc'], (s) => s.length > 1));
}
[2, 4]
[bb, ccc]

Remember: it is only a name #

Because a typedef is an alias, it gives no extra type safety. A Json and a Map<String, dynamic> are interchangeable. When you want a genuinely separate type, for example so that a UserId cannot be passed where an OrderId is expected, use an extension type or a class.

Try it yourself #

Create typedef Validator = String? Function(String input); where the function returns an error message, or null if the input is fine. Write two validators (not empty, at least 8 characters) and a function that runs a list of validators and returns the first error.

Practise in the playground Updated by Santosh Adhikari