Dart language guardrails, patterns, and best practices for AI-assisted development.
Use when working with Dart files (.dart), pubspec.yaml, or when the user mentions Dart/Flutter.
Provides null safety patterns, async/await guidelines, Flutter integration conventions,
and testing standards specific to this project's coding standards.
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Dart language guardrails, patterns, and best practices for AI-assisted development.
Use when working with Dart files (.dart), pubspec.yaml, or when the user mentions Dart/Flutter.
Provides null safety patterns, async/await guidelines, Flutter integration conventions,
and testing standards specific to this project's coding standards.
Never use ! (null assertion) without a preceding null check or guarantee
Use ? for nullable types only at API boundaries (JSON, platform channels)
Prefer ?? (if-null) and ?. (null-aware access) over explicit null checks
Use required keyword for non-optional named parameters
Use late only when initialization is guaranteed before access (avoid for laziness)
// BAD: crashes at runtime if null
final name = json['name'] as String;
// GOOD: explicit nullable handling
final name = json['name'] as String? ?? 'Unknown';
// GOOD: required parameter enforces non-null at call site
void createUser({required String name, required String email}) { ... }
// BAD: late used for laziness without guarantees
late final String config;
// GOOD: late with guaranteed initialization in constructor body
late final Database _db;
void init(Database db) => _db = db;
Async/Await
Always await Futures or return them; never fire-and-forget without error handling
Use async* and yield for Stream generators
Set timeouts on all external calls with .timeout(Duration(...))
Catch specific exceptions, not bare catch (e)
Use Completer only when bridging callback-based APIs to Futures
lib/src/ for private implementation; export public API from lib/my_package.dart
test/ mirrors lib/src/ directory structure
bin/ only for executable entry points
No business logic in main.dart (delegate to services)
Key Patterns
Records and Pattern Matching (Dart 3)
// Records: lightweight immutable tuples with named fields
typedef UserSummary = ({String name, String email, int age});
UserSummary fetchSummary() => (name: 'Alice', email: 'a@b.com', age: 30);
// Destructuring with pattern matching
final (name: userName, email: _, age: userAge) = fetchSummary();
// Switch expressions with patterns
String classify(Object value) => switch (value) {
int n when n < 0 => 'negative',
int n when n == 0 => 'zero',
int() => 'positive',
String s => 'string: $s',
(int x, int y) => 'point ($x, $y)',
_ => 'unknown',
};
Sealed Classes and Exhaustive Matching
sealed class Result<T> {
const Result();
}
final class Success<T> extends Result<T> {
final T value;
const Success(this.value);
}
final class Failure<T> extends Result<T> {
final String message;
final Object? error;
const Failure(this.message, [this.error]);
}
// Exhaustive switch: compiler enforces all subtypes handled
String describe<T>(Result<T> result) => switch (result) {
Success(:final value) => 'Success: $value',
Failure(:final message) => 'Failed: $message',
};
Extension Methods and Types
// Extension methods: add functionality to existing types
extension StringValidation on String {
bool get isValidEmail => RegExp(r'^[\w-.]+@[\w-]+\.\w+$').hasMatch(this);
String truncate(int maxLength) =>
length <= maxLength ? this : '${substring(0, maxLength)}...';
}
// Extension types (Dart 3.3): zero-cost type wrappers
extension type UserId(String value) {
UserId.generate() : value = Uuid().v4();
bool get isValid => value.isNotEmpty;
}
// Usage: compile-time type safety, zero runtime overhead
void fetchUser(UserId id) { ... }
fetchUser(UserId('abc-123'));
// fetchUser('raw-string'); // Compile error
Late Keyword (Correct Usage)
class ApiClient {
// GOOD: late for dependency injection with guaranteed init
late final HttpClient _client;
void configure(HttpClient client) {
_client = client;
}
// GOOD: late final for expensive one-time computation
late final Map<String, dynamic> _config = _loadConfig();
Map<String, dynamic> _loadConfig() {
// expensive operation, runs once on first access
return jsonDecode(File('config.json').readAsStringSync());
}
}
Stream Patterns
// async* generator for producing streams
Stream<int> countDown(int from) async* {
for (var i = from; i >= 0; i--) {
await Future.delayed(const Duration(seconds: 1));
yield i;
}
}
// Stream transformations
final results = inputStream
.where((event) => event.isValid)
.map((event) => event.transform())
.handleError((error) => logger.warning('Stream error: $error'))
.distinct();
Isolates for Heavy Computation
import 'dart:isolate';
// Simple one-shot isolate computation
Future<List<int>> computePrimes(int limit) async {
return await Isolate.run(() => _sieveOfEratosthenes(limit));
}
List<int> _sieveOfEratosthenes(int limit) {
final sieve = List.filled(limit + 1, true);
sieve[0] = sieve[1] = false;
for (var i = 2; i * i <= limit; i++) {
if (sieve[i]) {
for (var j = i * i; j <= limit; j += i) {
sieve[j] = false;
}
}
}
return [for (var i = 2; i <= limit; i++) if (sieve[i]) i];
}
Testing
Standards
Test files: *_test.dart in test/ (mirror lib/src/ structure)
Test functions: test('description of behavior', () { ... })
Group related tests: group('ClassName', () { ... })
Use package:test for pure Dart, package:flutter_test for widgets
Use package:mockito with @GenerateMocks for type-safe mocking
Coverage target: >80% for business logic, >60% overall
Test names describe behavior: 'returns empty list when no users exist'
Unit Test Pattern
import 'package:test/test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
@GenerateMocks([UserRepository])
import 'user_service_test.mocks.dart';
void main() {
late MockUserRepository mockRepo;
late UserService service;
setUp(() {
mockRepo = MockUserRepository();
service = UserService(mockRepo);
});
group('UserService', () {
group('getUser', () {
test('returns user when found', () async {
final expected = User(id: '1', name: 'Alice');
when(mockRepo.findById('1')).thenAnswer((_) async => expected);
final result = await service.getUser('1');
expect(result, isA<Success<User>>());
expect((result as Success).value, equals(expected));
verify(mockRepo.findById('1')).called(1);
});
test('returns failure when user not found', () async {
when(mockRepo.findById('99')).thenAnswer((_) async => null);
final result = await service.getUser('99');
expect(result, isA<Failure>());
expect((result as Failure).message, contains('not found'));
});
});
});
}
Async and Stream Testing
test('stream emits values in order', () {
expect(
countDown(3),
emitsInOrder([3, 2, 1, 0, emitsDone]),
);
});
test('completes within timeout', () async {
final result = await fetchData().timeout(const Duration(seconds: 5));
expect(result, isNotNull);
});
Tooling
Essential Commands
dart format . # Format all Dart files
dart analyze # Static analysis (lint + type checks)
dart test# Run all tests
dart test --coverage=coverage # Run tests with coverage
dart run bin/main.dart # Run CLI application
dart compile exe bin/main.dart # AOT compile to native executable
dart pub get # Install dependencies
dart pub outdated # Check for dependency updates
dart pub deps # Show dependency tree
dart fix --apply # Auto-apply suggested fixes