Dart - Using Triple Dot (...) Spread Operator Examples

This tutorial explains what is the triple dot (...) spread operator in Dart and how to use it.

Since version 2.3, Dart adds a new operator called spread which uses three dots (...) notations. It can be used to extend the elements of a Collection. The examples below show the usage of the notation on List, Set, and Map.

Usage on List

Prior to Dart 2.3, we have to use addAll to combine two List instances. Now, the spread operator makes it easier for us to do the same thing.

  List<int> l1 = [1, 2, 3];
  List<int> result = [0, ...l1];
  print(result);

In the example above, the result is generated by concatenating an element (0) with a List (l1).

Output:

  [0, 1, 2, 3]

 

You can also use triple dot for combining two List instances.

  List<int> l1 = [1, 2, 3];
  List<int> l2 = [4, 5];
  List<int> result = [...l1, ...l2];
  print(result);

Output:

  [1, 2, 3, 4, 5]

 

Nested assignment is also possible

  List<int> result = [...[0, ...l1, ...l2], 6];
  print(result);

First, it combines the 0 element with l1 and l2 which generates a List. The result is then concatenated to the outer List with the 6 element.

Output:

  [0, 1, 2, 3, 4, 5, 6]

What happens if you try to use the spread operator with a null List.

  List<int> nullList = null;
  List<int> result = [...l1, ...nullList];
  print(result);

You will get the following error:

  Unhandled exception:
  NoSuchMethodError: The getter 'iterator' was called on null.

Fortunately, Dart also supports null-aware operator for spread. Just add ? symbol after the triple dot ....

  List<int> nullList = null;
  List<int> result = [...l1, ...?nullList];
  print(result);

By using the null-aware operator, the value will be checked first and if it's null, it will be ignored.

Output:

  [1, 2, 3]

 

You can also use if condition to determine whether the List should be concatenated or not.

  bool condition = false;
  List<int> result = [...l1, if (condition) ...l2];
  print(result);

As the value of condition is false in the example above, l2 will be ignored.

 

It can also be used on Future by adding await after the triple dot (...) notation.

  Future<List<int>> l1 = Future.value([1, 2, 3]);
  Future<List<int>> l2 = Future.value([3, 4, 5]);
  List<int> result = [...await l1, ...await l2];
  print(result);

Output:

  [1, 2, 3, 4, 5]

 

Usage on Set

Spread operator can also be used on Set. You can combine multiple Set instances and the result is the union of all Set instances since a Set must have unique elements.

  Set<int> s1 = {1, 2, 3};
  Set<int> s2 = {3, 4, 5};
  Set<int> result = {...s1, ...s2};
  print(result);

Output:

  {1, 2, 3, 4, 5}


Using nested spread operator is also possible.

  Set<int> s1 = {1, 2, 3};
  Set<int> s2 = {3, 4, 5};
  Set<int> result = {...{...s1, ...s2}, 5, 6};
  print(result);

Output:

  {1, 2, 3, 4, 5, 6}

 

The operator will throw error when applied on a null Set.

  Set<int> s1 = {1, 2, 3};
  Set<int> nullSet = null;
  Set<int> result = {...s1, ...nullSet};
  print(result);
  Unhandled exception:
  NoSuchMethodError: The getter 'iterator' was called on null.

It can be handled using null-aware ? notation which ignores null value.

  Set<int> s1 = {1, 2, 3};
  Set<int> nullSet = null;
  Set<int> result = {...s1, ...?nullSet};
  print(result);

Output:

  {1, 2, 3}

 

if conditional is supported as well.

  Set<int> s1 = {1, 2, 3};
  Set<int> s2 = {3, 4, 5};
  bool condition = false;
  Set<int> result = {...s1, if (condition) ...s2};
  print(result);

Output:

  {1, 2, 3}

 

As does Future

  Future<Set<int>> s1 = Future.value({1, 2, 3});
  Future<Set<int>> s2 = Future.value({3, 4, 5});
  Set<int> result = {...await s1, ...await s2};
  print(result);

Output:

  {1, 2, 3, 4, 5}

 

Usage on Map

The spread operator can also be used for Map. What will happen if we try to combine multiple Map instances where a key can presence in more than one Map. To find the answer, look at the example below

  Map<int, String> m1 = {1: '1-1', 2: '1-2'};
  Map<int, String> m2 = {2: '2-2', 3: '2-3'};
  Map<int, String> result = {...m1, ...m2};
  print(result);

If you run the code, you will find that the value is always overridden by the latest Map.

Output:

  {1: 1-1, 2: 2-2, 3: 2-3}


Here is an example with nested spread operator.

  Map<int, String> m1 = {1: '1-1', 2: '1-2'};
  Map<int, String> m2 = {2: '2-2', 3: '2-3'};
  Map<int, String> result = {...{...m1, ...m2}, 3: '3', 4: '4'};
  print(result);

Output:

  {1: 1-1, 2: 2-2, 3: 3, 4: 4}

 

Like the other Collection types, applying triple dot on null will throw NoSuchMethodError.

  Map<int, String> m1 = {1: '1-1', 2: '1-2'};
  Map<int, String> nullMap = null;
  Map<int, String> result = {...m1, ...nullMap};
  print(result);
  Unhandled exception:
  NoSuchMethodError: The getter 'entries' was called on null.

And it can be handled using null-aware operator.

  Map<int, String> m1 = {1: '1-1', 2: '1-2'};
  Map<int, String> nullMap = null;
  Map<int, String> result = {...m1, ...?nullMap};
  print(result);

Output:

  {1: 1-1, 2: 1-2}

 

Using await is also possible if you need to get value from a Future.

  Future<Map<int, int>> future1 = Future.value({1: 1, 2: 2});
  Future<Map<int, int>> future2 = Future.value({3: 3});
  Map<int, int> result = {...await future1, ...await future2};
  print(result);

Output:

  {1: 1-1, 2: 2-2, 3: 2-3}

That's how to use the spread operator in Dart. It makes us easier to combine collections while also makes the code cleaner.