<< All versions
Skill v1.0.1
currentAutomated scan100/100sickn33/agentic-awesome-skills/dart
+4 new
──Details
PublishedOctober 27, 2026 at 11:19 AM
Content Hashsha256:2bb49dc8608f48ac...
Git SHA0f1aef1eb176
Bump Typepatch
──Files
Files (1 file, 7.8 KB)
SKILL.md7.8 KBactive
SKILL.md · 335 lines · 7.8 KB
name: dart description: "Language-specific super-code guidelines for dart." risk: safe source: community date_added: "2026-06-16" metadata: version: "1.0.1"
Dart: Idiomatic Efficiency Reference
Apply only within the requested scope and current project conventions. Preserve behavior, ownership, error handling, accessibility and security; examples are independent fragments, not equivalent rewrites in every context. Verify language/library versions and run relevant checks. Required tests and user-facing progress/results take precedence over brevity rules. Do not install dependencies or delete files merely to follow these examples.
When to Use
- Use this skill when the task matches this description: Language-specific super-code guidelines for dart.
Table of Contents
- Null Safety
- Collections & Iteration
- Classes & Records
- Async/Await & Streams
- Error Handling
- Flutter-Specific Patterns
- Anti-patterns specific to Dart
1. Null Safety {#nulls}
dart
// ❌ Manual null checkString display;if (user.name != null) {display = user.name!;} else {display = 'Unknown';}// ✅final display = user.name ?? 'Unknown';
dart
// ❌ Nested null checksif (user != null && user.address != null && user.address!.city != null) {print(user.address!.city!);}// ✅final city = user?.address?.city;if (city != null) print(city);
dart
// ❌ Late field when nullable is correctlate String name; // crashes if accessed before assignment// ✅ — use late only when you guarantee initialization before accessString? name; // honestly nullable// late is fine for: late final _controller = TextEditingController();
dart
// ❌ Bang operator (!) everywherefinal name = user.name!;final city = user.address!.city!;// ✅ — promote through null checksfinal name = user.name;if (name == null) return;// name is now non-null (promoted)
2. Collections & Iteration {#collections}
dart
// ❌ Imperative accumulationfinal result = <String>[];for (final item in items) {if (item.isActive) result.add(item.name.toUpperCase());}// ✅final result = items.where((i) => i.isActive).map((i) => i.name.toUpperCase()).toList();
dart
// ❌ Manual map constructionfinal map = <String, List<Item>>{};for (final item in items) {map.putIfAbsent(item.category, () => []).add(item);}// ✅ (using collection-if/for in a different way — but groupBy isn't built-in)// The loop above is actually idiomatic Dart. Use package:collection for groupBy:import 'package:collection/collection.dart';final map = groupBy(items, (Item i) => i.category);
dart
// ❌ Building list with add() callsfinal widgets = <Widget>[];widgets.add(Header());if (showSubtitle) widgets.add(Subtitle());widgets.add(Body());// ✅ — collection-iffinal widgets = [Header(),if (showSubtitle) Subtitle(),Body(),];
dart
// ❌ Spreading manuallyfinal all = <int>[];all.addAll(listA);all.addAll(listB);// ✅final all = [...listA, ...listB];
3. Classes & Records {#classes}
dart
// ❌ Manual data class boilerplateclass Point {final int x, y;const Point(this.x, this.y);@override bool operator ==(Object other) => ...@override int get hashCode => ...@override String toString() => 'Point($x, $y)';}// ✅ (Dart 3.0+)typedef Point = ({int x, int y});// or for named class semantics:class Point {final int x, y;const Point(this.x, this.y);}// Use package:equatable or Dart records for equality
dart
// ❌ Verbose constructorclass User {final String name;final int age;User(String name, int age) : name = name, age = age;}// ✅ — initializing formalsclass User {final String name;final int age;const User(this.name, this.age);}
dart
// ❌ Mutable fields on an immutable objectclass Config {String host;int port;Config(this.host, this.port);}// ✅class Config {final String host;final int port;const Config(this.host, this.port);}
dart
// ❌ Switch on type with if-else chainif (shape is Circle) {return (shape as Circle).radius * pi;} else if (shape is Rectangle) { ... }// ✅ (Dart 3.0+)return switch (shape) {Circle(:final radius) => radius * radius * pi,Rectangle(:final width, :final height) => width * height,};
4. Async/Await & Streams {#async}
dart
// ❌ .then() chainsfetchUser().then((user) => fetchPosts(user)).then((posts) => display(posts)).catchError((e) => log(e));// ✅try {final user = await fetchUser();final posts = await fetchPosts(user);display(posts);} catch (e) {log(e);}
dart
// ❌ Sequential await for independent workfinal a = await fetchA();final b = await fetchB();// ✅final results = await Future.wait([fetchA(), fetchB()]);// or with typed destructuring:final (a, b) = await (fetchA(), fetchB()).wait; // Dart 3.3+ record Future.wait extension
dart
// ❌ StreamBuilder doing too much in buildStreamBuilder(stream: stream,builder: (ctx, snap) {if (snap.hasError) return Error();if (!snap.hasData) return Loading();final data = snap.data!;// 50 lines of widget tree...},)// ✅ — extract widget, or use listen + setState for simple cases
5. Error Handling {#errors}
dart
// ❌ Catching Exception (too broad)try { process(); }on Exception catch (e) { print(e); }// ✅ — catch specific typestry {process();} on FormatException catch (e) {throw AppException('Invalid format', cause: e);} on HttpException catch (e) {throw AppException('Network error', cause: e);}
dart
// ❌ Returning null for errorsFuture<User?> fetchUser() async {try { return await api.getUser(); }catch (_) { return null; } // caller doesn't know why}// ✅ — let exceptions propagate, or use sealed Result typesealed class Result<T> {}class Success<T> extends Result<T> { final T value; Success(this.value); }class Failure<T> extends Result<T> { final Object error; Failure(this.error); }
6. Flutter-Specific Patterns {#flutter}
dart
// ❌ Rebuilding entire tree on state changesetState(() {// changes a single value, but the build() method builds 200 widgets});// ✅ — extract subtrees into separate widgets or use ValueListenableBuilderValueListenableBuilder<int>(valueListenable: counter,builder: (_, value, __) => Text('$value'),)
dart
// ❌ const-able widget without constContainer(color: Colors.blue)// ✅const ColoredBox(color: Colors.blue)// Mark constructors const when possible; use `const` keyword at call site
dart
// ❌ Navigator.push with MaterialPageRoute everywhereNavigator.push(context, MaterialPageRoute(builder: (_) => DetailPage()));// ✅ — named routes or GoRoutercontext.push('/detail'); // GoRouter; preserves push/back-stack intent
7. Anti-patterns specific to Dart {#antipatterns}
| Anti-pattern | Preferred | |
|---|---|---|
! (bang) operator liberally | null checks and promotion | |
dynamic everywhere | proper types | |
as cast without check | pattern matching or is check | |
| Mutable fields on value objects | final fields | |
print() for logging | package:logging or structured logger | |
Manual ==/hashCode | records, equatable, or code generation | |
setState for complex state | Riverpod / Bloc / Provider | |
| Deep widget nesting | extract widgets into classes | |
| String-based routing | typed routing (GoRouter) | |
late as escape hatch | nullable types or proper initialization | |
Future.delayed for debounce | Timer or proper debounce utility |
Limitations
- These are language-specific guidelines and do not cover overall architectural decisions.
- Over-compression might reduce readability; apply judgement.