Lesson 1 of 77 beginner

Dart Types, Null Safety & Variables

The Foundation Every Interviewer Tests First

Open interactive version (quiz + challenge)

Real-world analogy

Think of Dart types like labeled containers in a warehouse. A container labeled 'Fragile Glass' (String?) might be empty (null) or hold glass. Null safety is the warehouse rule that forces you to check if a container is empty before reaching in — preventing the classic 'I grabbed nothing and dropped it' crash.

What is it?

Dart's type system with null safety is the foundation of every Flutter app. Variables must have types (explicit or inferred), and null safety ensures you handle the absence of values explicitly with ? syntax rather than crashing at runtime. final/const/late control mutability and initialization timing.

Real-world relevance

In a real-time collaboration app, null safety prevents crashes when a user's profile hasn't loaded yet. Instead of crashing on user.name when user is null, the compiler forces you to handle it: user?.name ?? 'Loading...'. This pattern appears in every production Flutter app.

Key points

Code example

// Dart Types & Null Safety — Interview Essentials

// Non-nullable by default (Dart 2.12+)
String name = 'Flutter Dev';     // CANNOT be null
// name = null;                   // Compile error!

// Nullable with ?
String? nickname;                 // CAN be null
nickname = null;                  // OK
nickname = 'Coder';               // Also OK

// final vs const vs late
final DateTime now = DateTime.now();     // Runtime constant
const double pi = 3.14159;               // Compile-time constant
late final String config;                // Initialized before first use

// late with lazy initialization
late final String heavyValue = _computeExpensiveValue();

// Null-aware operators
String display = nickname ?? 'Anonymous';        // ?? null coalesce
int? length = nickname?.length;                  // ?. null-aware access
nickname ??= 'DefaultNick';                      // ??= assign if null

// Type promotion (flow analysis)
void greet(String? input) {
  if (input == null) return;
  // Dart promotes input from String? to String here
  print(input.toUpperCase());  // No ! needed
}

// The dangerous ! operator
String forced = nickname!;  // Crashes if null!

// num hierarchy
num value = 42;         // Can hold int or double
int whole = 5 ~/ 2;     // 2 (integer division)
double half = 5 / 2;    // 2.5 (always double)

// String interpolation
String greeting = 'Hello, $name! Length: ${name.length}';
String multiLine = '''
  This is a
  multi-line string
''';

// dynamic vs Object?
dynamic anything = 'hello';
anything = 42;           // OK — no type safety
anything.noSuchMethod(); // Compiles! Crashes at runtime.

Object? safe = 'hello';
// safe.length;          // Compile error — must check type first
if (safe is String) {
  print(safe.length);    // OK — type promoted to String
}

Line-by-line walkthrough

  1. 1. Declaring a non-nullable String — this variable can NEVER hold null
  2. 2. Attempting to assign null would cause a compile error — this is null safety in action
  3. 3. Declaring a nullable String? — the question mark means null is allowed
  4. 4. Assigning null is perfectly fine for nullable types
  5. 5. Reassigning to a real value is also fine
  6. 6. final creates a runtime constant — DateTime.now() runs when the line executes
  7. 7. const creates a compile-time constant — the value must be known at compile time
  8. 8. late tells Dart this will be initialized before first use
  9. 9. late with an initializer — the function only runs when heavyValue is first accessed
  10. 10. The ?? operator provides a fallback value when the left side is null
  11. 11. The ?. operator safely accesses a property — returns null if the object is null
  12. 12. The ??= operator assigns only if the current value is null
  13. 13. Type promotion: after the null check, Dart knows input is non-null String
  14. 14. The ! operator forces a nullable to non-nullable — crashes if actually null

Spot the bug

void processUser(String? name) {
  print(name.toUpperCase());
  
  final List<int> numbers = const [1, 2, 3];
  numbers.add(4);
  
  late String greeting;
  print(greeting);
}
Need a hint?
Three bugs: null safety violation, const immutability, and late initialization...
Show answer
Bug 1: name is String? but .toUpperCase() is called without null check — use name?.toUpperCase() or add a null guard. Bug 2: numbers is a const list, so .add(4) throws at runtime — remove const or use a mutable list. Bug 3: greeting is late but never assigned before print — assign it first or you get a LateInitializationError.

Explain like I'm 5

Imagine you have a lunchbox. Null safety is like a rule that says: before you eat from ANY lunchbox, you MUST check if there's food inside. Without this rule, you'd bite into an empty box and break your teeth. With it, you always check first: 'Is there food? Yes? Great, eat it. No? Get something else.'

Fun fact

Tony Hoare, who invented null references in 1965, called it his 'billion dollar mistake' because of all the crashes it caused. Dart's null safety was specifically designed to fix this mistake — and it works. Apps with null safety have significantly fewer null-related crashes in production.

Hands-on challenge

Create a User class with non-nullable name and email fields, a nullable phone field, and a method displayInfo() that uses null-aware operators to show 'No phone' when phone is null. Use final for immutable fields.

More resources

Open interactive version (quiz + challenge) ← Back to course: Flutter Interview Mastery