Data Types and Variables in Dart: A Complete Guide

Dart is a powerful, object-oriented programming language developed by Google, primarily used for building mobile, web, and desktop applications with Flutter. Understanding Dart’s data types and variables is fundamental to writing effective Dart code. In this comprehensive guide, we’ll explore everything you need to know about Dart’s type system and variable declarations.

What Are Data Types?

Dart Data Types and Variables

Data types define what kind of data a variable can store and what operations can be performed on that data. Dart is a statically typed language, which means the type of a variable is known at compile time, helping catch errors early and improving code performance.

Variable Declaration in Dart

Before diving into specific data types, let’s understand how to declare variables in Dart:

// Explicit type declaration
int age = 25;
String name = "John Doe";

// Type inference using var
var city = "New York"; // Dart infers this as String
var population = 8000000; // Dart infers this as int

// Using dynamic for flexible typing
dynamic flexibleVar = "Hello";
flexibleVar = 42; // This is allowed with dynamic

Built-in Data Types in Dart

1. Numbers

Dart provides two main numeric types:

int (Integers)

Represents whole numbers without decimal points.

int score = 100;
int negativeNumber = -42;
int hexValue = 0xFF; // Hexadecimal

double (Floating-point numbers)

Represents numbers with decimal points.

double price = 19.99;
double pi = 3.14159;
double scientific = 1.42e5; // Scientific notation

num (Parent class)

Both int and double inherit from num, allowing you to work with both types:

num temperature = 98.6; // Can be int or double
num count = 5;

2. Strings

Strings represent sequences of characters and are immutable in Dart.

String greeting = "Hello, World!";
String multiline = '''
This is a
multiline string
in Dart
''';

// String interpolation
String name = "Alice";
int age = 30;
String message = "My name is $name and I'm $age years old";
String expression = "Next year I'll be ${age + 1}";

3. Booleans

Booleans represent true or false values.

bool isActive = true;
bool isComplete = false;

// Boolean expressions
bool canVote = age >= 18;
bool isEligible = isActive && canVote;

4. Lists (Arrays)

Lists are ordered collections of objects.

// List of integers
List<int> numbers = [1, 2, 3, 4, 5];

// List of strings
List<String> fruits = ["apple", "banana", "orange"];

// Mixed list using dynamic
List<dynamic> mixed = [1, "hello", true, 3.14];

// Using var with type inference
var colors = ["red", "green", "blue"]; // Inferred as List<String>

// List operations
numbers.add(6);
fruits.remove("banana");
print(numbers.length); // 6

5. Maps

Maps are collections of key-value pairs, similar to dictionaries or hash tables.

// String keys with dynamic values
Map<String, dynamic> person = {
  "name": "John",
  "age": 25,
  "isEmployed": true
};

// String keys with string values
Map<String, String> capitals = {
  "USA": "Washington D.C.",
  "France": "Paris",
  "Japan": "Tokyo"
};

// Accessing and modifying maps
print(person["name"]); // John
person["city"] = "New York";
capitals.remove("Japan");

6. Sets

Sets are unordered collections of unique objects.

Set<String> uniqueNames = {"Alice", "Bob", "Charlie"};
Set<int> uniqueNumbers = {1, 2, 3, 3, 4}; // Duplicate 3 will be ignored

// Set operations
uniqueNames.add("David");
uniqueNumbers.remove(2);
bool containsAlice = uniqueNames.contains("Alice"); // true

7. Runes

Runes represent Unicode code points of a string.

String emoji = "πŸ˜€πŸŽ‰πŸš€";
Runes runes = emoji.runes;
print(runes.toList()); // [128512, 127881, 128640]

8. Symbols

Symbols represent operators or identifiers declared in a Dart program.

Symbol symbol1 = #mySymbol;
Symbol symbol2 = Symbol('anotherSymbol');

Special Types

Null Safety

Dart 2.12 introduced null safety, making variables non-nullable by default:

// Non-nullable types
String name = "John"; // Cannot be null
int age = 25; // Cannot be null

// Nullable types (with ?)
String? nickname; // Can be null
int? optionalId; // Can be null

// Null assertion operator (!)
String? possiblyNull = getName();
String definitelyNotNull = possiblyNull!; // Throws if null

// Null-aware operator (??)
String displayName = nickname ?? "Anonymous";

late Keyword

The late keyword allows you to declare non-nullable variables that are initialized later:

late String description;
late final int computedValue;

void initializeValues() {
  description = "This is initialized later";
  computedValue = expensiveComputation();
}

final and const

final

Creates a variable that can only be set once:

final String appName = "MyApp";
final DateTime now = DateTime.now(); // Set at runtime
// appName = "NewName"; // Error: can't reassign

const

Creates compile-time constants:

const double pi = 3.14159;
const List<String> colors = ["red", "green", "blue"];
// const DateTime now = DateTime.now(); // Error: not compile-time constant

Type Conversion and Casting

Dart provides methods to convert between types:

// String to number
String ageStr = "25";
int age = int.parse(ageStr);
double price = double.parse("19.99");

// Number to string
String ageString = age.toString();
String priceString = price.toStringAsFixed(2); // "19.99"

// Type casting
dynamic value = "Hello";
String str = value as String; // Safe if you're sure it's a String

// Type checking
if (value is String) {
  print("It's a string: ${value.length}");
}

Best Practices

1. Use Type Inference When Appropriate

// Good: Clear and concise
var name = "John";
var numbers = [1, 2, 3];

// Also good: Explicit when needed
Map<String, List<int>> userScores = {};

2. Leverage Null Safety

// Good: Use nullable types when necessary
String? getUserInput() {
  // May return null
  return null;
}

// Good: Handle null values safely
String input = getUserInput() ?? "default";

3. Choose Appropriate Collection Types

// Use List for ordered, indexed access
List<String> todoItems = ["Buy milk", "Walk dog"];

// Use Set for unique items
Set<String> uniqueTags = {"flutter", "dart", "mobile"};

// Use Map for key-value relationships
Map<String, int> wordCount = {"hello": 5, "world": 3};

4. Use const for Immutable Values

// Good: Use const for compile-time constants
const String apiUrl = "https://api.example.com";
const List<String> supportedLanguages = ["en", "es", "fr"];

Common Pitfalls and How to Avoid Them

1. Null Safety Violations

// Bad: Might cause null pointer exception
String? name = getName();
print(name.length); // Error if name is null

// Good: Check for null first
if (name != null) {
  print(name.length);
}

// Or use null-aware operator
print(name?.length ?? 0);

2. Type Mismatches

// Bad: Runtime error
dynamic value = "123";
int number = value; // Error: String is not int

// Good: Proper conversion
int number = int.parse(value as String);

3. Unnecessary Type Declarations

// Verbose: Unnecessary explicit typing
String name = String.fromCharCode(72); // Dart can infer this

// Better: Let Dart infer
var name = String.fromCharCode(72);

Conclusion

Understanding Dart’s data types and variables is crucial for writing robust, maintainable applications. The language’s strong type system, combined with null safety and type inference, helps catch errors early while keeping code clean and readable.

Key takeaways:

  • Dart offers a rich set of built-in data types for different use cases
  • Null safety helps prevent common runtime errors
  • Type inference reduces boilerplate while maintaining type safety
  • Choose the right collection type (List, Set, Map) based on your needs
  • Use final and const appropriately for immutable data

As you continue your Dart journey, remember that mastering these fundamentals will make you more productive and help you write better Flutter applications. Practice with different data types, experiment with null safety features, and always consider the most appropriate type for your specific use case.

Whether you’re building mobile apps with Flutter, web applications, or server-side solutions, a solid understanding of Dart’s data types and variables will serve as the foundation for all your future development endeavors.

Read More: HTTP Error Handling in Flutter: A Complete Guide

Leave a Reply

Your email address will not be published. Required fields are marked *