dart-best-practices
General best practices for Dart development. Covers code style, effective Dart, and language features.
Guidelines for using modern Dart features (v3.0 - v3.10) such as Records, Extension Types, Class Modifiers, Wildcards, Digit Separators, Null-Aware Elements, and Dot Shorthands.
$ npx -y skills add kevmoo/dash_skills --skill dart-modern-features --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/dart-modern-featuresContext preview
The summary Claude sees to decide when to auto-load this skill.
Guidelines for using modern Dart features (v3.0 - v3.10) such as Records, Extension Types, Class Modifiers, Wildcards, Digit Separators, Null-Aware Elements, and Dot Shorthands.
name: dart-modern-features description: |- Guidelines for using modern Dart features (v3.0 - v3.10) such as Records, Extension Types, Class Modifiers, Wildcards, Digit Separators, Null-Aware Elements, and Dot Shorthands. key_features: - Records & Extension Types - Class Modifiers & Wildcards - Null-aware elements & Dot shorthands
Use this skill when:
such as records, extension types, class modifiers, null-aware collection elements, dot shorthands, and digit separators.
domain wrappers.
For pattern matching, switch expressions, and list/map/split destructuring, use **[dart-use-pattern-matching]**. For converting closed class hierarchies into exhaustive `sealed` types, use **[dart-seal-type-hierarchies]**.
Do NOT apply modern features or refactor code when:
constraint that supports Dart 2.x (e.g., `sdk: '>=2.19.0 <4.0.0'`). Refactoring to Dart 3 features will introduce syntax errors for Dart 2 users.
values or internal tuples, but complex public API payloads are clearer and more extensible as dedicated classes or extension types.
To find candidates for modernization:
Search for collection `if` statements checking for null:
Search for long numbers without separators:
Use records as anonymous, immutable, aggregate structures to bundle multiple objects without defining a custom class. Prefer them for returning multiple values from a function or grouping related data temporarily.
**Avoid:** Creating a dedicated class for simple multiple-value returns.
class UserResult {
final String name;
final int age;
UserResult(this.name, this.age);
}
UserResult fetchUser() {
return UserResult('Alice', 42);
}**Prefer:** Using records to bundle types seamlessly on the fly.
(String, int) fetchUser() {
return ('Alice', 42);
}
void main() {
var user = fetchUser();
print(user.$1); // Alice
}Use class modifiers (`final`, `base`, `interface`, `sealed`) to restrict how classes can be subtyped outside their defining library:
(preserving private implementation invariants).
exhaustive switching (see **[dart-seal-type-hierarchies]**).
**Avoid:** Leaving internal implementation classes open to arbitrary external subclassing or interface implementation when invariants must be enforced.
class TokenStore {
void save(String token) {}
}**Prefer:** Declaring explicit subtyping capabilities with class modifiers.
final class TokenStore {
void save(String token) {}
}Use extension types for a zero-cost wrapper around an existing type. Use them to restrict operations or add custom behavior without runtime overhead.
**Avoid:** Allocating new wrapper objects just for domain-specific logic or type safety.
class Id {
final int value;
Id(this.value);
bool get isValid => value > 0;
}**Prefer:** Using extension types which compile down to the underlying type at runtime.
extension type Id(int value) {
bool get isValid => value > 0;
}Use underscores (`_`) in number literals strictly to improve visual readability of large numeric values.
**Avoid:** Long number literals that are difficult to read at a glance.
const int oneMillion = 1000000;
**Prefer:** Using underscores to separate thousands or other groupings.
const int oneMillion = 1_000_000;
Use wildcards (`_`) as non-binding variables or parameters to explicitly signal that a value is intentionally unused.
**Avoid:** Inventing clunky, distinct variable names to avoid "unused variable" warnings.
void handleEvent(String ignoredName, int status) {
print('Status: $status');
}**Prefer:** Explicitly dropping the binding with an underscore.
void handleEvent(String _, int status) {
print('Status: $status');
}Use null-aware elements (`?`) inside collection literals to conditionally include items only if they evaluate to a non-null value.
**Avoid:** Using collection `if` statements for simple null checks.
var names = [ 'Alice', if (optionalName != null) optionalName, 'Charlie' ];
**Prefer:** Using the `?` prefix inline.
var names = ['Alice', ?optionalName, 'Charlie'];
Use dot shorthands to omit the explicit type name when it can be confidently inferred from context, such as with enums or static fields.
**Avoid:** Fully qualifying type names when the type is obvious from the context.
LogLevel currentLevel = LogLevel.info;
**Prefer:** Reducing visual noise with inferred shorthand.
LogLevel currentLevel = .info;
matching, switch expressions, and list/map/`String.split()` destructuring.
`sealed` types for exhaustive switching.
General best practices for Dart development. Covers code style, effective Dart, and language features.
Best practices for validating Dart documentation comments. Covers using `dart doc` to catch unresolved references and macros.
Guidelines for handling long lines in Dart code to adhere to the 80-column rule. The `lines_longer_than_80_chars` lint.
Best practices for using `expect` and `package:matcher`. Focuses on readable assertions, proper matcher selection, and avoiding…
Guidelines and best practices for refactoring consecutive prints, single-line string concatenations, and complex output blocks…
Guidelines for maintaining external Dart packages, covering versioning, publishing workflows, and pull request management. Use…