dart-fix-runtime-errors

dart-fix-runtime-errors

熱門

使用 get_runtime_errors 與 lsp 擷取當前的 stack trace,定位出錯的程式碼行,進行修復並透過 hot_reload 驗證問題是否已解決。

2792星標
164分支
更新於 2026/8/5
SKILL.md
唯讀
名稱
dart-fix-runtime-errors
描述

使用 get_runtime_errors 與 lsp 擷取當前的 stack trace,定位出錯的程式碼行,進行修復並透過 hot_reload 驗證問題是否已解決。

解決 Dart 靜態分析錯誤

目錄

核心概念與規範

型別系統與健全性

落實 Dart 健全的型別系統(Sound Type System),防止程式在執行時期進入無效狀態。

  • Method Overrides(方法覆寫): 確保回傳型別具備共變性(covariant),參數型別具備逆變性(contravariant)。除非明確加上 covariant 關鍵字,否則絕不可在子類別中縮窄參數型別的範圍。
  • Generics & Collections(泛型與集合): 為泛型類別明確加上型別標註(例如 List<T>Map<K, V>)。切勿將 List<dynamic> 指派給指定型別的清單(例如 List<Cat>)。
  • Downcasting(向下轉型): 避免從 dynamic 進行隱式向下轉型。必要時請使用顯式轉型(例如 as List<Cat>),但必須確保執行時期的底層型別符合,以免引發 TypeError 例外。
  • Strict Casts(嚴格轉型):analysis_options.yamlanalyzer: language: 設定下啟用 strict-casts: true,強制要求顯式轉型,並在編譯時期即時攔截隱式向下轉型錯誤。

空值安全性

透過正確管理變數的初始化與可空性(Nullability),徹底消除與空值安全性(Null Safety)相關的靜態錯誤。

  • Modifiers(修飾詞): 使用 ? 表示可空型別,使用 ! 進行非空斷言,對不可為 null 的具名參數加上 required
  • Late Initialization(延遲初始化): 對於保證在存取前會完成初始化的非空變數,使用 late 關鍵字。這特別適用於 Dart 控制流分析無法明確證明其已初始化的頂層變數或實例變數。
  • Wildcards(萬用字元): 對於不需要繫結的區域變數或參數,使用 _ 萬用字元(Dart 3.7+),避免觸發未被使用的變數警告。

錯誤處理

區分可復原的例外(Exceptions)與不可復原的錯誤(Errors)。

  • Catching(擷取): 只針對可復原的失敗擷取 Exception 的子型別。
  • Errors(錯誤): 絕不要主動擷取 Error 或其子型別(例如 TypeErrorArgumentError)。Error 代表程式設計上的 Bug,應直接修正程式碼而非捕捉例外。請啟用 avoid_catching_errors linter 規則來強制貫徹此標準。
  • Rethrowing(重新拋出):catch 區塊中使用 rethrow 重新傳播例外,以完整保留原始 stack trace。

工作流程

工作流程:靜態分析錯誤修復

請依序執行以下工作流程,以找出、修復並驗證 Dart 專案中的靜態分析錯誤。你可以複製此檢核表來追蹤進度。

任務進度:

  • [ ] 1. 執行靜態分析器。
  • [ ] 2. 套用自動修復。
  • [ ] 3. 手動修復剩餘錯誤。
  • [ ] 4. 驗證修復結果(回饋迴圈)。

1. 執行靜態分析器
執行 Dart 分析器,找出目標目錄或檔案中的所有靜態錯誤。

dart analyze . --fatal-infos

2. 套用自動修復
使用 dart fix 工具自動解決標準的代码檢查(linting)與分析問題。

# 預覽變更
dart fix --dry-run
# 套用變更
dart fix --apply

3. 手動修復剩餘錯誤
檢視分析器輸出的剩餘訊息,並根據錯誤類型採取相應邏輯:

  • 若錯誤屬於空值安全性問題(例如 "Property cannot be accessed on a nullable receiver"):
    • 確認該變數在邏輯上是否可能為 null。
    • 若可能,請使用可空鏈接(?.)或提供備用值(??)。
    • 若不可能且會在其他地方完成初始化,請在宣告時加上 late 修飾詞。
  • 若錯誤屬於型別不符問題(例如 "The argument type 'List<dynamic>' can't be assigned..."):
    • 追蹤該變數的初始化流程。
    • 在實例化時明確標註泛型型別(例如使用 <int>[] 替代 [])。
  • 若錯誤屬於無效覆寫問題(例如 "The parameter type doesn't match the overridden method"):
    • 放寬參數型別以符合父類別,或
    • 若領域邏輯明確需要縮窄型別,請在參數加上 covariant 關鍵字。

4. 驗證修復結果(回饋迴圈)
執行驗證工具,檢視錯誤並修復。

dart analyze .
dart test
  • dart analyze 仍回報錯誤: 返回步驟 3。
  • dart testTypeError 失敗: 代表加入了無效的顯式轉型(as T)或存取了尚未初始化的 late 變數。請定位執行時期的錯誤位置,並修復型別階層或初始化順序。

範例

範例:修復 Dynamic List 指派錯誤

輸入(未通過靜態分析):

void printInts(List<int> a) => print(a);

void main() {
  final list = []; // 被推導為 List<dynamic>
  list.add(1);
  list.add(2);
  printInts(list); // 錯誤:無法將 List<dynamic> 指派給 List<int>
}

輸出(通過靜態分析):

void printInts(List<int> a) => print(a);

void main() {
  final list = <int>[]; // 明確標註型別
  list.add(1);
  list.add(2);
  printInts(list);
}

範例:修復方法覆寫錯誤(逆變性)

輸入(未通過靜態分析):

class Animal {
  void chase(Animal a) {}
}

class Cat extends Animal {
  @override
  void chase(Mouse a) {} // 錯誤:縮窄了參數型別
}

輸出(通過靜態分析):

class Animal {
  void chase(Animal a) {}
}

class Cat extends Animal {
  @override
  void chase(covariant Mouse a) {} // 明確標記為 covariant
}

範例:使用 late 修飾詞修復空值安全性問題

輸入(未通過靜態分析):

class Thermometer {
  String temperature; // 錯誤:不可為 null 的實例欄位必須進行初始化

  void read() {
    temperature = '20C';
  }
}

輸出(通過靜態分析):

class Thermometer {
  late String temperature; // 將初始化檢查延遲至執行時期

  void read() {
    temperature = '20C';
  }
}