Class Modifiers
Prerequisites: Sealed classes and exhaustive switching, Interfaces and implements
By default, any Dart class can be created, extended, and implemented by anyone. Dart 3's class modifiers let a library author restrict that — which matters most when publishing packages others depend on.
The modifiers
| Modifier | Outside the library, the class can be... |
|---|---|
| (none) | created, extended, and implemented |
abstract |
extended and implemented, but not created directly |
base |
created and extended, but not implemented |
interface |
created and implemented, but not extended |
final |
created only — not extended or implemented |
sealed |
none of these — and switches over it are exhaustive |
mixin class |
used as both a class and a mixin |
These restrictions apply outside the library (file) where the class is declared; inside it, you can still extend and implement freely. That's why a sealed class's subclasses must live in the same file.
Why restrict?
// In your package:
final class Money {
final int cents;
const Money(this.cents);
}
interface class PaymentGateway {
Future<bool> charge(int cents) async => true;
}
base class Repository {
void save() => print('saved');
}
final class Money— nobody can subclassMoneyand change its behavior, so your code can trust anyMoneyvalue. You're also free to add members later without breaking anyone.interface class PaymentGateway— users implement it (for example, with a fake in tests), but can't inherit from your implementation and depend on its internals.base class Repository— subclasses must inherit your implementation, which guarantees your internal logic always runs.
A user of the package who tries class MyMoney extends Money {} gets a
compile error explaining that Money can't be extended outside its
library.
Modifiers can be combined: abstract interface class is the Dart 3 way
to declare a pure interface.
Do you need them?
In application code, rarely — except sealed, which is valuable
everywhere for exhaustive switching. In packages, they let you evolve
your API safely. Choose the most restrictive modifier that still allows
what your users need; you can always loosen it later without breaking
anyone, but not the other way round.