mcpField
D
dart-language-syntax

dart-language-syntax

github.com/dart-lang開発53273 回インストール2 週間前に更新
リポジトリ

dart-language-syntax について

Dart 開発者やコーディングエージェント向けのスキルです。状態管理、関数、レコード、パターン、ジェネリクスを通じて、慣用的な Dart の記述と近代化を支援します。

主な機能

  1. 01var、final、const の使い分け
  2. 02ティアオフとジェネレーターの活用
  3. 03レコードによる複数値の返却と分解
  4. 04パターンと switch 式の活用
  5. 05型安全なジェネリックコードの作成

活用シーン

  1. 01既存の Dart コードの近代化
  2. 02タプルクラスをレコードに置き換え
  3. 03パターンによる JSON の検証
  4. 04switch 式による条件分岐のリファクタリング

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dart-lang/skills --skill dart-language-syntax

インストール後、Claude Code で/dart-language-syntaxを入力して読み込まれたか確認します。

詳細

慣用的な Dart の書き方

目次

変数と状態管理

厳格な可変性と型推論のルールに従って、状態と変数宣言を管理します。

  • var を優先する: 代入される型が明らかな場合は、ローカル変数に var を使用します(例:var name = 'Bob';)。初期化式から型がすぐに明らかにならない場合は、明示的な型を使用します。
  • 不変性を徹底する: 初期化後に再代入しない変数には final を使用します。コンパイル時定数や、正準化された不変のオブジェクトインスタンスを作成する場合は const を使用します。
  • late を活用する: late 修飾子を使うと、null 非許容変数の初期化を初回使用時まで遅らせられます。特に、計算コストが高い場合や、初期化に this へのアクセスが必要な場合に有効です。
  • ワイルドカードを使用する: ローカル宣言、クロージャ、パターンマッチングで未使用の値を破棄するには、ワイルドカード変数 _(Dart 3.7 以降が必要)を使用します。これにより、未使用変数の警告を回避できます。

関数とクロージャ

合成可能性を最大限に高め、ボイラープレートを最小限に抑えるよう関数を構成します。

  • アロー構文を使用する: => 演算子を使って、単一式の関数を簡潔に記述します。
  • ティアオフを優先する: 関数参照(ティアオフ)を、冗長な匿名クロージャでラップせずに直接渡します(例:list.forEach((e) => print(e)) の代わりに list.forEach(print) を使用します)。
  • ジェネレーターを実装する: sync* を使って Iterable シーケンスを遅延生成し、async* を使って Stream シーケンスを生成します。yield で値を生成するか、yield* で他のジェネレーターに処理を委譲します。
  • 名前付きパラメーターを定義する: 呼び出し箇所の可読性を高めるため、真偽値のフラグや複数の引数を持つ関数には、名前付きパラメーター ({required Type name}) を使用します。

レコードとパターンマッチング

レコードとパターンを使って、ボイラープレートのデータクラスや複雑な条件分岐をなくします。

  • 複数の値を返す: 専用のクラスを定義せずに関数から複数の値を返すには、レコード (Type, Type) を使用します。
  • 代入を分解する: パターンマッチングを活用して、レコード、リスト、オブジェクトをローカル変数に直接分解します。
  • switch 式を使用する: 複雑な if-else の連鎖を switch 式に置き換えます。論理和パターン(||)やガード節(when)を活用して、ケース間でロジックを共有します。
  • JSON を宣言的に検証する: マップパターンとリストパターンを使って、動的な JSON ペイロードの構造を検証し、型を確認してデータを抽出します。

ジェネリクスと型安全性

コレクションやカスタムコンポーネント全体で、型安全性と再利用性を確保します。

  • ジェネリクスを実装する: クラス、メソッド、コレクションをパラメーター化するには <T> を使用します。
  • 型パラメーターを制約する: ジェネリック型に上限を設けるには extends を使用します(例:null 非許容性を強制する <T extends Object> や、<T extends BaseWidget>)。
  • F境界を使用する: クラスが自身と完全に同じ型のインスタンスとやり取りする必要がある場合は、自己参照型の制約を実装します(例:class Node<T extends Node<T>>)。
  • 機能を拡張する: サブクラス化せずに、拡張メソッドや拡張型を使って、既存のジェネリッククラスや具象クラスにユーティリティ関数を追加します。

ワークフロー:慣用的な Dart へのリファクタリング

このチェックリストを使って、レガシーな Dart コードを最新の慣用的な Dart 3 以降の標準にアップグレードします。

  • タスクの進捗:変数の最新化
    • 明らかなローカル代入では、明示的な型を var に置き換えます。
    • 再代入されない可変な var 宣言を final に変更します。
    • 未使用のパラメーターに使われている __ または ___ を、標準の _ ワイルドカードに置き換えます。
  • タスクの進捗:制御フローと戻り値
    • 独自の「Tuple」または「Pair」クラスを、ネイティブの Record (T1, T2) に置き換えます。
    • 冗長なクロージャを関数またはメソッドのティアオフにリファクタリングします。
    • 1 つの文だけで構成される関数本体を、アロー構文 => に変更します。
  • タスクの進捗:パターンマッチングの導入
    • オブジェクトから複数のフィールドを取り出す場合は、オブジェクトの分割代入を使います:var User(:name, :age) = user;。
    • ネストされた JSON を検証する場合は、is チェックと手動のキャストをマップ/リストパターンに置き換えます。
    • 代数的データ型(シールドクラス)を切り替える場合は、switch 文を網羅的な switch 式に変更します。
  • バリデーターの実行 → エラーの確認 → 修正: dart analyze と dart format を実行します。型の昇格または網羅性に関する lint エラーを解決します。

例

複数の戻り値の分割代入(Records)

入力(レガシー):

class UserInfo {
  final String name;
  final int age;
  UserInfo(this.name, this.age);
}

UserInfo fetchUser() => UserInfo('Dash', 10);
final info = fetchUser();
print(info.name);

出力(慣用的な書き方):

(String, int) fetchUser() => ('Dash', 10);

// Destructure directly into final variables
final (name, age) = fetchUser();
print(name);
宣言的な JSON 検証(パターン)

入力(レガシー):

if (json is Map<String, Object?> && json.containsKey('user')) {
  var user = json['user'];
  if (user is List<Object> && user.length == 2 && user[0] is String && user[1] is int) {
    var name = user[0] as String;
    var age = user[1] as int;
    print('User $name is $age');
  }
}

出力(慣用的な書き方):

if (json case {'user': [String name, int age]}) {
  print('User $name is $age');
}
Switch 式とガード節

実装:

sealed class Shape {}
class Square implements Shape { final double length; Square(this.length); }
class Circle implements Shape { final double radius; Circle(this.radius); }

double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) when l > 0 => l * l,
  Circle(:var radius) when radius > 0 => 3.14159 * radius * radius,
  _ => 0.0, // Fallback for invalid dimensions
};
ジェネリクスを使った拡張メソッド

実装:

extension IterableExtensions<T> on Iterable<T> {
  /// Returns the first element matching the predicate, or null.
  T? firstWhereOrNull(bool Function(T) test) {
    for (final element in this) {
      if (test(element)) return element;
    }
    return null;
  }
}

コメント