$npx -y skills add kevmoo/dash_skills --skill dart-modern-featuresGuidelines for using modern Dart features (v3.0 - v3.10) such as Records, Pattern Matching, Switch Expressions, Extension Types, Class Modifiers, Wildcards, Null-Aware Elements, and Dot Shorthands.
| 1 | # Dart Modern Features |
| 2 | |
| 3 | ## 1. When to use this skill |
| 4 | |
| 5 | Use this skill when: |
| 6 | - Writing or reviewing Dart code targeting Dart 3.0 or later. |
| 7 | - Refactoring legacy Dart code to use modern, concise, and safe features. |
| 8 | - Looking for idiomatic ways to handle multiple return values, deep data |
| 9 | extraction, or exhaustive checking. |
| 10 | |
| 11 | ## Discovery |
| 12 | |
| 13 | To find candidates for modernization: |
| 14 | |
| 15 | ### Switch Expressions |
| 16 | Search for switch statements where every case assigns to the same variable |
| 17 | or returns: |
| 18 | - **Regex**: `switch\s*\([^)]+\)\s*\{\s*case` |
| 19 | |
| 20 | ### Pattern Matching Candidates |
| 21 | Search for manual map or JSON property extraction and type checking: |
| 22 | - **Regex**: `containsKey\(['"][^'"]+['"]\)` |
| 23 | - **Regex**: `json\[['"][^'"]+['"]\]\s+is\s+` |
| 24 | |
| 25 | ### Null-Aware Elements |
| 26 | Search for collection `if` statements checking for null: |
| 27 | - **Regex**: `if\s*\(\w+\s*!=\s*null\)\s*\w+` |
| 28 | |
| 29 | ### Digit Separators |
| 30 | Search for long numbers without separators: |
| 31 | - **Regex**: `\b\d{6,}\b` (Matches numbers with 6 or more digits). |
| 32 | |
| 33 | ## 2. Features |
| 34 | |
| 35 | ### Records |
| 36 | Use records as anonymous, immutable, aggregate structures to bundle multiple |
| 37 | objects without defining a custom class. Prefer them for returning multiple |
| 38 | values from a function or grouping related data temporarily. |
| 39 | |
| 40 | **Avoid:** |
| 41 | Creating a dedicated class for simple multiple-value returns. |
| 42 | ```dart |
| 43 | class UserResult { |
| 44 | final String name; |
| 45 | final int age; |
| 46 | UserResult(this.name, this.age); |
| 47 | } |
| 48 | |
| 49 | UserResult fetchUser() { |
| 50 | return UserResult('Alice', 42); |
| 51 | } |
| 52 | ``` |
| 53 | |
| 54 | **Prefer:** |
| 55 | Using records to bundle types seamlessly on the fly. |
| 56 | ```dart |
| 57 | (String, int) fetchUser() { |
| 58 | return ('Alice', 42); |
| 59 | } |
| 60 | |
| 61 | void main() { |
| 62 | var user = fetchUser(); |
| 63 | print(user.$1); // Alice |
| 64 | } |
| 65 | ``` |
| 66 | |
| 67 | ### Patterns and Pattern Matching |
| 68 | Use patterns to destructure complex data into local variables and match against |
| 69 | specific shapes or values. Use them in `switch`, `if-case`, or variable |
| 70 | declarations to unpack data directly. |
| 71 | |
| 72 | **Avoid:** |
| 73 | Manually checking types, nulls, and keys for data extraction. |
| 74 | ```dart |
| 75 | void processJson(Map<String, dynamic> json) { |
| 76 | if (json.containsKey('name') && json['name'] is String && |
| 77 | json.containsKey('age') && json['age'] is int) { |
| 78 | String name = json['name']; |
| 79 | int age = json['age']; |
| 80 | print('$name is $age years old.'); |
| 81 | } |
| 82 | } |
| 83 | ``` |
| 84 | |
| 85 | **Prefer:** |
| 86 | Combining type-checking, validation, and assignment into a single statement. |
| 87 | ```dart |
| 88 | void processJson(Map<String, dynamic> json) { |
| 89 | if (json case {'name': String name, 'age': int age}) { |
| 90 | print('$name is $age years old.'); |
| 91 | } |
| 92 | } |
| 93 | ``` |
| 94 | |
| 95 | ### Switch Expressions |
| 96 | Use switch expressions to return a value directly, eliminating bulky `case` and |
| 97 | `break` statements. |
| 98 | |
| 99 | **Avoid:** |
| 100 | Using switch statements where every branch simply returns or assigns a value. |
| 101 | ```dart |
| 102 | String describeStatus(int code) { |
| 103 | switch (code) { |
| 104 | case 200: |
| 105 | return 'Success'; |
| 106 | case 404: |
| 107 | return 'Not Found'; |
| 108 | default: |
| 109 | return 'Unknown'; |
| 110 | } |
| 111 | } |
| 112 | ``` |
| 113 | |
| 114 | **Prefer:** |
| 115 | Returning the evaluated expression directly using the `=>` syntax. |
| 116 | ```dart |
| 117 | String describeStatus(int code) => switch (code) { |
| 118 | 200 => 'Success', |
| 119 | 404 => 'Not Found', |
| 120 | _ => 'Unknown', |
| 121 | }; |
| 122 | ``` |
| 123 | |
| 124 | ### Class Modifiers |
| 125 | Use class modifiers (`sealed`, `final`, `base`, `interface`) to restrict how |
| 126 | classes can be used outside their defines library. Prefer `sealed` for defining |
| 127 | closed families of subtypes to enable exhaustive checking. |
| 128 | |
| 129 | **Avoid:** |
| 130 | Using open `abstract` classes when the set of subclasses is known and fixed. |
| 131 | ```dart |
| 132 | abstract class Result {} |
| 133 | |
| 134 | class Success extends Result {} |
| 135 | class Failure extends Result {} |
| 136 | |
| 137 | String handle(Result r) { |
| 138 | if (r is Success) return 'OK'; |
| 139 | if (r is Failure) return 'Error'; |
| 140 | return 'Unknown'; |
| 141 | } |
| 142 | ``` |
| 143 | |
| 144 | **Prefer:** |
| 145 | Using `sealed` to guarantee to the compiler that all cases are covered. |
| 146 | ```dart |
| 147 | sealed class Result {} |
| 148 | |
| 149 | class Success extends Result {} |
| 150 | class Failure extends Result {} |
| 151 | |
| 152 | String handle(Result r) => switch(r) { |
| 153 | Success() => 'OK', |
| 154 | Failure() => 'Error', |
| 155 | }; |
| 156 | ``` |
| 157 | |
| 158 | ### Extension Types |
| 159 | Use extension types for a zero-cost wrapper around an existing type. Use them to |
| 160 | restrict operations or add custom behavior without runtime overhead. |
| 161 | |
| 162 | **Avoid:** |
| 163 | Allocating new wrapper objects just for domain-specific logic or type safety. |
| 164 | ```dart |
| 165 | class Id { |
| 166 | final int value; |
| 167 | Id(this.value); |
| 168 | bool get isValid => value > 0; |
| 169 | } |
| 170 | ``` |
| 171 | |
| 172 | **Prefer:** |
| 173 | Using extension types which compile down to the underlying type at runtime. |
| 174 | ```dart |
| 175 | extension type Id(int value) { |
| 176 | bool get isValid => value > 0; |
| 177 | } |
| 178 | ``` |
| 179 | |
| 180 | ### Digit Separators |
| 181 | Use underscores (`_`) in number literals strictly to improve visual readability |
| 182 | of large numeric values. |
| 183 | |
| 184 | **Avoid:** |
| 185 | Long number literals that are d |