In our last session, we focused on how Dart structures code using classes, constructors, and mixins, drawing parallels to your experience with C++ and JavaScript. Now, we'll shift our attention from structuring code to structuring and processing data. This lesson is where your JavaScript/TypeScript background will be particularly beneficial.
Today, we'll explore three cornerstone concepts of data handling in Dart:
- Collections: The fundamental data structures like
List,Set, andMap. - Generics: The mechanism for writing type-safe code that works with collections and more.
- Higher-Order Functions: Powerful methods like
map,where, andfoldthat allow for expressive, functional-style data manipulation.
By the end of this lesson, you'll be able to manage and transform data in Dart with the same fluency you have in JavaScript, but with the added benefits of Dart's strong type system.
Dart's Core Collections
Just as JavaScript has Array, Set, and Map, Dart provides a rich set of collection libraries. The three most important interfaces you'll work with are List, Set, and Map.
List: An ordered collection of items, similar to a JavaScriptArray. It's the most common collection you'll use.Set: An unordered collection of unique items.Map: A collection of key-value pairs, analogous to a JavaScriptMapor a plainObject.
The following diagram provides a high-level overview of the collection types in Dart, showing the relationship between the abstract interfaces and the concrete classes that implement them.

For a developer coming from JavaScript, the official Dart documentation has an excellent guide that maps these concepts directly to what you already know.
Learning Dart as a JavaScript developer
This guide from the official Dart website is tailored for developers with a JavaScript background. It provides clear, comparative examples for Dart's collection types.
Please read the entire "Collections" section. As you read, focus on the following: List literals, which are identical to JS array literals. The methods for manipulating lists, such as add, insert, remove, and how they compare to JS array methods like push, splice, and pop. The subtle syntax for creating an empty Set (<String>{}) versus an empty Map ({}). The examples for Maps, which should feel very familiar. The powerful in-line control flow features like collection if/for and the spread operator (...), which are modern additions to both languages.
After this reading, you should feel comfortable creating and performing basic operations on Dart's primary collections.
Type Safety with Generics
You've likely noticed the angle brackets in List<String> or Map<String, int>. This is Dart's syntax for generics. Your experience with TypeScript has already prepared you for this concept: generics allow us to write code that is both reusable and type-safe. Instead of a List that can hold any type (like a raw JavaScript array), a List<int> can only hold integers, and the compiler will enforce this.

Using generics helps catch errors at compile time rather than at runtime, leading to more robust and predictable applications. The following video offers a fantastic deep dive into how generics work in Dart and why they are preferable to using the dynamic type.
#17 - Dart Generics, Generic Types, Generic Classes, Generic Methods
This Flutterly video, "Dart Generics," breaks down the concept from first principles and shows practical applications.
Watch the introduction from the beginning. This segment explains the fundamental purpose of generics: to create reusable code (like the List class) without sacrificing type safety. Next, jump to the section on generic methods. This demonstrates how to create your own generic functions, moving from a type-specific implementation to a more abstract, reusable one. Finally, watch the crucial explanation of the difference between generics and dynamic. This highlights why generics provide superior static safety, a concept that aligns perfectly with the benefits of TypeScript over plain JavaScript.
To solidify this, here's a short text from the same JS-to-Dart guide you read earlier, summarizing generics from a practical standpoint.
Learning Dart as a JavaScript developer
This section provides a concise textual reference on generics in Dart.
Read the section on "Generics". Pay attention to the syntax for generic methods and generic classes. Also, note how the extends keyword can be used to restrict generics, similar to generic constraints in TypeScript.
Functional-Style Data Processing
Now that you know how to create and type-check collections, let's explore the powerful, declarative ways Dart allows you to process them. If you've used array.map(), array.filter(), and array.reduce() in JavaScript, you're already familiar with the paradigm of higher-order functions: functions that take other functions as arguments.
This functional approach leads to code that is often more concise and readable than traditional imperative loops.
Practical Functional Programming in Dart & Flutter - Reso Coder
This article from Reso Coder provides a great conceptual introduction to why you'd choose a functional style over an imperative one for data manipulation.
Read the first two sections, "Imperative vs Functional Programming" and "More Complex Example." The examples clearly contrast a for loop with the fold (Dart's reduce) and map methods, showing how the functional approach can be cleaner and more composable.
With the "why" established, let's dive into the "how." The video below is an excellent, practical walkthrough of Dart's most common higher-order functions for collections.
1.9) forEach(), map(), fold(), reduce() | Complete (FREE) Flutter Course
This video from Algo Alchemy provides a code-focused tutorial on Dart's most useful collection methods.
Start with the explanation of map() from this timestamp. This is for transforming each element in a collection. Pay close attention to the fact that map returns an Iterable, and you often need to call .toList() to get a List back. Next, watch the segment on where() from this section. This is Dart's equivalent of JavaScript's filter(), used for selecting elements that meet a certain condition. Then, watch the walkthrough of reduce() and fold() from here. These are used to combine a collection into a single value. The video does a great job explaining the key difference: fold lets you provide an initial value, making it more versatile and safer than reduce, which uses the first element as the initial value. This is directly analogous to how reduce works in JavaScript. Optionally, watch the final recap to reinforce your understanding of all the methods covered.
Let's see this in action. Imagine you have a list of numbers and you want to get the sum of the squares of only the even numbers.
Imperative approach with a for loop:
void main() {
final numbers = [1, 2, 3, 4, 5, 6];
var sum = 0;
for (final number in numbers) {
if (number % 2 == 0) {
sum += number * number;
}
}
print(sum); // Prints 56 (4 + 16 + 36)
}
Functional approach with higher-order functions:
void main() {
final numbers = [1, 2, 3, 4, 5, 6];
final sum = numbers
.where((n) => n % 2 == 0) // Filter: [2, 4, 6]
.map((n) => n * n) // Transform: [4, 16, 36]
.fold(0, (prev, n) => prev + n); // Reduce: 0 + 4 + 16 + 36
print(sum); // Prints 56
}
As you can see, the functional approach reads as a clear sequence of data transformations and is often preferred in modern Dart and Flutter code.
Conclusion
In this lesson, you've learned how to effectively manage and process data in Dart. We've leveraged your existing JavaScript/TypeScript knowledge to quickly get you up to speed with Dart's powerful features.
Here are the key takeaways:
- Collections (
List,Set,Map) are the primary data structures for holding groups of objects. - Generics (
<T>) are essential for writing type-safe code, preventing a wide class of bugs by enforcing type constraints at compile time. - Higher-Order Functions (
map,where,fold) enable a declarative, functional style of programming that leads to more concise and expressive data manipulation code.
We've now covered object-oriented programming and functional data processing, two major pillars of the Dart language. In the next lesson, we will tackle another crucial topic: asynchronous programming. You'll learn how to use Future, async, and await to handle operations like network requests, which will feel very similar to JavaScript's Promise-based workflow.