Type system
- Dart course
- Expert
- Lesson 3/47
- 5 min
Learn the Dart type system and variance.
The type system
Dart's type system is static and sound: every expression has a type known at compile time. Object is the supertype of all objects, while dynamic defers checks to runtime.
Generic types (List<int>, Map<String, int>) let the same container work with different types. Variance rules (covariance, contravariance) govern subtype relationships of generic types.
Generic types
Generic types let a class or function work with different types. class Box<T> { final T value; Box(this.value); } allows usages like Box<int>, Box<String>.
The type parameter T is substituted with the actual type. Generics reduce code duplication and keep type safety: trying to extract a String from a Box<int> is a compile error.
Practice A generic Box class
Define a generic Box<T> class with final T value; field, Box(this.value); constructor and T unwrap() => value; method. In main create final box = Box<String>('Merhaba');; print the result with print(box.unwrap());.
Starter code
void main() {
// define a Box<T> generic class (value field; unwrap method)
// create a Box<String>; print unwrap() result
}Sample solution
class Box<T> {
final T value;
Box(this.value);
T unwrap() => value;
}
void main() {
final box = Box<String>('Merhaba');
print(box.unwrap());
}Expected output
Merhaba
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Match the type system concepts
| Term | Meaning |
|---|---|
Object |
Supertype of all |
dynamic |
Runtime checking |
List<int> |
Integer list |
Map<String, int> |
Key-value mapping |
2 What is the difference between dynamic and Object?
- They are the same
- dynamic only holds numbers
- Object only holds class instances
- dynamic defers all type checks to runtime Correct answer
Explanation: Object checks at compile time.
3 Generic Box declaration
class Box<T> {
final T value;
Box(this.value);
}
void main() {
final box = Box<____>(42);
print(box.value);
}
class Box<T> {
final T value;
Box(this.value);
}
void main() {
final box = Box<int>(42);
print(box.value);
}
Explanation: Box<int> creates an integer box and value returns 42.