Dart Quick Reference

Dart language essentials for Flutter development — types, collections, async, null safety, and common patterns

Dart is the language behind Flutter. This reference covers the patterns you’ll use every day.

Variables and types

// Immutable (prefer this)
final name = 'Alice';          // type inferred, set once
final int age = 30;             // explicit type

// Compile-time constant
const pi = 3.14159;
const defaultTimeout = Duration(seconds: 30);

// Mutable
var count = 0;                  // type inferred
String greeting = 'hello';     // explicit type

// Nullable (Dart null safety)
String? maybeNull;             // can be null
int? maybeInt;                  // can be null
String alwaysValue = 'hello';  // cannot be null

// Late initialization
late String description;        // will be set before first use
late final ThemeData theme;    // will be set once

Collections

// List
var fruits = ['apple', 'banana', 'cherry'];   // List<String>
fruits.add('date');
fruits.remove('banana');
fruits[0];                    // 'apple'
fruits.length;                // 3
fruits.isEmpty;
fruits.contains('apple');     // true

var nums = [1, 2, 3, 4, 5];
nums.where((n) => n > 2);                    // (3, 4, 5) - Iterable
nums.map((n) => n * 2);                      // (2, 4, 6, 8, 10)
nums.reduce((a, b) => a + b);                // 15
nums.fold(0, (acc, n) => acc + n);           // 15
nums.any((n) => n > 4);                      // true
nums.every((n) => n > 0);                    // true
nums.forEach((n) => print(n));
var evens = nums.where((n) => n.isEven).toList(); // [2, 4]

// Set
var set = <String>{'apple', 'banana'};
set.add('cherry');
set.contains('apple');        // true

// Map
var scores = {'Alice': 95, 'Bob': 87};        // Map<String, int>
scores['Charlie'] = 92;
scores['Alice'];               // 95
scores.containsKey('Bob');     // true
scores.keys;                   // ('Alice', 'Bob', 'Charlie')
scores.values;                 // (95, 87, 92)
scores.forEach((k, v) => print('$k: $v'));

// Spread and collection-if
var combined = [...fruits, ...['date', 'elderberry']];
var positives = nums.where((n) => n > 0).toList();
var withHeader = ['Header', if (showItems) ...items];

Functions

// Named parameters (prefer for clarity)
void createUser({required String name, int age = 0, String? email}) {
  print('$name, $age, $email');
}
createUser(name: 'Alice', age: 30);

// Positional parameters
String greet(String name, [String? title]) {
  return 'Hello, ${title ?? ""} $name';
}
greet('Alice');              // 'Hello,  Alice'
greet('Alice', 'Dr.');       // 'Hello, Dr. Alice'

// Arrow functions
int square(int n) => n * n;
bool isAdult(int age) => age >= 18;

// Typedef for function types
typedef Validator = String? Function(String? value);

Classes

class User {
  final String name;
  final int age;
  String? email;

  // Constructor
  User({required this.name, required this.age, this.email});

  // Named constructor
  User.guest() : name = 'Guest', age = 0;

  // Factory constructor
  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'] as String,
      age: json['age'] as int,
      email: json['email'] as String?,
    );
  }

  // Method
  String greet() => 'Hi, I\'m $name';

  // Override
  @override
  String toString() => 'User($name, $age)';

  // Getter
  bool get isAdult => age >= 18;
}

// Abstract class
abstract class Repository {
  Future<List<User>> getAll();
  Future<User> getById(String id);
}

// Implementing (implements)
class InMemoryRepository implements Repository {
  final List<User> _users = [];

  @override
  Future<List<User>> getAll() async => _users;

  @override
  Future<User> getById(String id) async =>
      _users.firstWhere((u) => u.name == id);
}

// Extending (inherits)
class Admin extends User {
  final List<String> permissions;

  Admin({required String name, required int age, this.permissions = const []})
      : super(name: name, age: age);
}

// Mixin — share behavior across classes
mixin Loggable {
  void log(String message) => print('[${DateTime.now()}] $message');
}

class Service with Loggable {
  void doWork() {
    log('Starting work');
  }
}

Enums

enum Status { pending, active, completed }

// Enhanced enums (Dart 2.17+)
enum Weather {
  sunny(icon: '☀️', temp: 30),
  cloudy(icon: '☁️', temp: 20),
  rainy(icon: '🌧️', temp: 15);

  final String icon;
  final int temp;

  const Weather({required this.icon, required this.temp});
}

// Pattern matching on enums
String describe(Status s) => switch (s) {
  Status.pending => 'Waiting...',
  Status.active => 'In progress',
  Status.completed => 'Done!',
};

Async / Await

// Future — a value available later
Future<String> fetchName() async {
  await Future.delayed(Duration(seconds: 1));
  return 'Alice';
}

// Multiple futures in parallel
final results = await Future.wait([
  fetchUsers(),
  fetchPosts(),
]);

// Streams — a sequence of async values
Stream<int> countStream(int max) async* {
  for (int i = 1; i <= max; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

// Listen to a stream
final subscription = countStream(5).listen(
  (value) => print(value),
  onError: (e) => print('Error: $e'),
  onDone: () => print('Done'),
);

// await for
await for (final value in countStream(3)) {
  print(value);
}

Null safety patterns

// Safe call
name?.length;                    // null if name is null

// Null coalesce
final display = name ?? 'Unknown';

// Null assertion (use sparingly)
final length = name!.length;     // throws if null

// Conditional property access
list?.length ?? 0;               // 0 if list is null

// Null-aware spread
var items = [...?nullableList];  // spreads if not null, empty otherwise

// Null-aware cascade
object?..method()..anotherMethod();

Pattern matching (Dart 3)

// Switch expressions
String describe(Object value) => switch (value) {
  int() => 'integer: $value',
  String() => 'string: $value',
  List() => 'list with ${value.length} items',
  _ => 'unknown',
};

// Destructuring
class Point(final double x, final double y);

void printPoint(Point p) {
  var (:x, :y) = p;
  print('($x, $y)');
}

// Map pattern
if (json case {'name': String name, 'age': int age}) {
  print('$name is $age');
}

// List pattern
if (items case [first, ...rest]) {
  print('First: $first, Rest: $rest');
}