dart-3-updates
Applies Dart 3 language features in Flutter/Dart code. Use when writing if-else or switch statements, creating new classes, or deciding between a data class and a record.
Best use case
dart-3-updates is best used when you need a repeatable AI agent workflow instead of a one-off prompt. It is especially useful for teams working in multi. Applies Dart 3 language features in Flutter/Dart code. Use when writing if-else or switch statements, creating new classes, or deciding between a data class and a record.
Applies Dart 3 language features in Flutter/Dart code. Use when writing if-else or switch statements, creating new classes, or deciding between a data class and a record.
Users should expect a more consistent workflow output, faster repeated execution, and less time spent rewriting prompts from scratch.
Practical example
Example input
Use the "dart-3-updates" skill to help with this workflow task. Context: Applies Dart 3 language features in Flutter/Dart code. Use when writing if-else or switch statements, creating new classes, or deciding between a data class and a record.
Example output
A structured workflow result with clearer steps, more consistent formatting, and an output that is easier to reuse in the next run.
When to use this skill
- Use this skill when you want a reusable workflow rather than writing the same prompt again and again.
When not to use this skill
- Do not use this when you only need a one-off answer and do not need a reusable workflow.
- Do not use it if you cannot install or maintain the related files, repository context, or supporting tools.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/dart-3-updates/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How dart-3-updates Compares
| Feature / Agent | dart-3-updates | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Applies Dart 3 language features in Flutter/Dart code. Use when writing if-else or switch statements, creating new classes, or deciding between a data class and a record.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Dart 3 Updates Skill
This skill defines how to correctly use Dart 3 language features: branches, patterns, pattern types, and records.
---
## 1. Branches
### if / if-case
```dart
// Standard if
if (score >= 90) {
grade = 'A';
} else if (score >= 80) {
grade = 'B';
} else {
grade = 'C';
}
// if-case: match and destructure against a single pattern
if (pair case [int x, int y]) {
print('$x, $y');
}
```
- `if` conditions must evaluate to a `bool`.
- In `if-case`, variables declared in the pattern are scoped to the matching branch.
- If the pattern does not match, control flows to the `else` branch (if present).
### switch statements
```dart
switch (command) {
case 'quit':
quit();
case 'start' || 'begin': // logical-or pattern
startGame();
default:
print('Unknown command');
}
```
- Each matched `case` body executes and jumps to the end — `break` is **not required**.
- Non-empty cases can end with `continue`, `throw`, or `return`.
- Use `default` or `_` to handle unmatched values.
- Empty cases fall through; use `break` to prevent fallthrough in an empty case.
- Use `continue` with a label for non-sequential fallthrough.
- Use logical-or patterns (`case a || b`) to share a body between cases.
### switch expressions
```dart
final color = switch (shape) {
Circle() => 'red',
Square() => 'blue',
_ => 'unknown',
};
```
- Omit `case`; use `=>` for bodies; separate cases with commas.
- Default must use `_` (not `default`).
- Produces a value.
### Exhaustiveness
- Dart checks exhaustiveness in `switch` statements and expressions at compile time.
- Use `default`/`_`, enums, or `sealed` types to satisfy exhaustiveness.
```dart
sealed class Shape {}
class Circle extends Shape {}
class Square extends Shape {}
// Dart knows all subtypes — no default needed:
String describe(Shape s) => switch (s) {
Circle() => 'circle',
Square() => 'square',
};
```
### Guard clauses
```dart
switch (point) {
case (int x, int y) when x == y:
print('Diagonal: $x');
case (int x, int y):
print('$x, $y');
}
```
- Add `when condition` after a pattern to further constrain matching.
- Usable in `if-case`, `switch` statements, and `switch` expressions.
- If the guard is `false`, execution proceeds to the next case.
---
## 2. Patterns
Patterns represent the **shape** of a value for matching and destructuring.
### Uses
```dart
// Variable declaration
var (a, [b, c]) = ('str', [1, 2]);
// Variable assignment (swap)
(b, a) = (a, b);
// for-in loop destructuring
for (final MapEntry(:key, :value) in map.entries) { ... }
// switch / if-case (see Branches section)
```
- Wildcard `_` ignores parts of a matched value.
- Rest elements (`...`) in list patterns ignore remaining elements.
- Case patterns are **refutable**: if no match, execution continues to the next case.
- Destructured values in a case become local variables scoped to that case body.
### Object patterns
```dart
var Foo(:one, :two) = myFoo;
```
### JSON / nested data validation
```dart
if (data case {'user': [String name, int age]}) {
print('$name, $age');
}
```
---
## 3. Pattern Types
| Pattern | Syntax | Description |
|---|---|---|
| Logical-or | `p1 \|\| p2` | Matches if any branch matches. All branches must bind the same variables. |
| Logical-and | `p1 && p2` | Matches if both match. Variable names must not overlap. |
| Relational | `== c`, `< c`, `>= c` | Compares value to a constant. Combine with `&&` for ranges. |
| Cast | `subpattern as Type` | Asserts type, then matches inner pattern. Throws if type mismatch. |
| Null-check | `subpattern?` | Matches non-null; binds non-nullable type. |
| Null-assert | `subpattern!` | Matches non-null or throws. Use in declarations to eliminate nulls. |
| Constant | `42`, `'str'`, `const Foo()` | Matches if value equals the constant. |
| Variable | `var name`, `final Type name` | Binds matched value to a new variable. Typed form only matches the declared type. |
| Wildcard | `_`, `Type _` | Matches any value without binding. |
| Parenthesized | `(subpattern)` | Controls precedence. |
| List | `[p1, p2]` | Matches lists by position. Length must match unless a rest element is used. |
| Rest element | `...`, `...rest` | Matches arbitrary-length tails or collects remaining elements. |
| Map | `{'key': subpattern}` | Matches maps by key. Missing keys throw `StateError`. |
| Record | `(p1, p2)`, `(x: p1, y: p2)` | Matches records by shape; field names can be omitted if inferred. |
| Object | `ClassName(field: p)` | Matches by type and destructures via getters. Extra fields ignored. |
- Use parentheses to group lower-precedence patterns.
- All pattern types can be **nested and combined**.
---
## 4. Records
```dart
// Create
var record = ('first', a: 2, b: true, 'last');
// Type annotation
({int a, bool b}) namedRecord;
// Access
print(record.$1); // positional: 'first'
print(record.a); // named: 2
```
- Records are **anonymous, immutable, fixed-size** aggregates.
- Each field can have a different type (heterogeneous).
- Fields are accessed via built-in getters (`$1`, `$2`, `.name`); no setters.
- Two records are equal if they have the same shape and equal field values.
- `hashCode` and `==` are automatically defined.
### Multiple return values
```dart
(String name, int age) userInfo(Map<String, dynamic> json) {
return (json['name'] as String, json['age'] as int);
}
var (name, age) = userInfo(json);
// Named fields:
final (:name, :age) = userInfo(json);
```
### Records vs. data classes
Use a **record** when:
- Returning multiple values from a single function (small, one-time use).
- Grouping a few values locally with no reuse across the codebase.
- You need structural equality with no additional behavior.
Use a **class** when:
- The type is reused across multiple files or features.
- You need methods, encapsulation, inheritance, or `copyWith`.
- The type is part of a public API or long-lived data model.
- Changing the shape must be caught by the type system across the codebase.
### Other best practices
- Use `typedef` for record types to improve readability and maintainability.
- Changing a record type alias does not guarantee type safety across the codebase — only classes provide full abstraction.
---Related Skills
effective-dart
Applies Effective Dart guidelines in Flutter/Dart code. Use when writing or reviewing Dart code for naming conventions, types, style, imports, file structure, usage patterns, documentation, testing, widgets, state management, or performance.
testing
Writes and reviews Flutter/Dart tests. Use when writing unit tests, widget tests, or reviewing existing tests for correctness, structure, and naming conventions.
riverpod
Uses Riverpod for state management in Flutter/Dart. Use when setting up providers, combining requests, managing state disposal, passing arguments, performing side effects, testing providers, or applying Riverpod best practices.
provider
Uses the Provider package for dependency injection and state management in Flutter. Use when setting up providers, consuming state, optimizing rebuilds, using ProxyProvider, or migrating from deprecated providers.
patrol-e2e-testing
Generates and maintains end-to-end tests for Flutter apps using Patrol. Use when adding E2E coverage for new features, regression tests for UI bugs, or testing native interactions (permissions, system dialogs, deep links)
mocktail
Uses the Mocktail package for mocking in Flutter/Dart tests. Use when creating mocks, stubbing methods, verifying interactions, registering fallback values, or deciding between mocks, fakes, and real objects.
mockito
Uses the Mockito package for mocking in Flutter/Dart tests. Use when generating mocks, stubbing methods, verifying interactions, capturing arguments, or deciding between mocks, fakes, and real objects.
flutterfire-configure
Sets up Firebase for Flutter apps using FlutterFire CLI. Use when initializing a Firebase project, running flutterfire configure, initializing Firebase in main.dart, or configuring multiple app flavors.
flutter-errors
Diagnoses and fixes common Flutter errors. Use when encountering layout errors (RenderFlex overflow, unbounded constraints, RenderBox not laid out), scroll errors, or setState-during-build errors.
flutter-app-architecture
Provides best practices for Flutter app architecture, including layered architecture, data flow, state management patterns, and extensibility guidelines.
firebase-storage
Integrates Firebase Cloud Storage into Flutter apps. Use when setting up Storage, uploading or downloading files, managing metadata, handling errors, or applying security rules.
firebase-remote-config
Integrates Firebase Remote Config into Flutter apps. Use when setting up Remote Config, managing parameter defaults, fetching and activating values, implementing real-time updates, or handling throttling and testing.