Rules / Suspicious / avoid-dynamic

avoid-dynamic

lint/suspicious/avoid-dynamic
recommended
Same as avoid-dynamic · Dart Code Metrics

Flags explicit dynamic type annotations.

dynamic opts an expression out of static type checking, so member accesses and calls on it are resolved at runtime and any mistake surfaces as a crash rather than a compile error. Reaching for it is usually a shortcut where a concrete type, a generic, or Object? plus explicit checks would be safer. Prefer a precise type. dynamic used directly as a Map type argument — the documented JSON escape hatch, Map<String, dynamic> — is exempt, but a dynamic nested more deeply (such as Map<String, List<dynamic>>) is still flagged.

Invalid

example.dartdart
// Test cases for avoid-dynamic rule
// All violations are annotated inline

void testDynamicVariable() {
  dynamic x = 5;
  dynamic name = "test";
  dynamic list = [1, 2, 3];
}

void testDynamicParameters(dynamic arg, dynamic other) {
  print(arg);
  print(other);
}

Future<dynamic> asyncMethod() {
  return Future.value(42);
}

dynamic returnDynamic() {
  return "anything";
}

class TestClass {
  dynamic field;

  void method(dynamic param) {
    final dynamic local = param;
  }
}

// `dynamic` as a type argument of a non-Map generic is still flagged, and a
// `dynamic` nested one level below `Map` (inside `List`) is NOT exempt: only a
// direct `Map<_, dynamic>` argument is.
List<dynamic> listOfDynamic = [];

Route<dynamic>? routeField;

Map<String, List<dynamic>> nested = {};
Avoid using the 'dynamic' type
4void testDynamicVariable() {
5 dynamic x = 5;
Avoid using the 'dynamic' type
5 dynamic x = 5;
6 dynamic name = "test";
Avoid using the 'dynamic' type
6 dynamic name = "test";
7 dynamic list = [1, 2, 3];
Avoid using the 'dynamic' type
9
10void testDynamicParameters(dynamic arg, dynamic other) {
Avoid using the 'dynamic' type
9
10void testDynamicParameters(dynamic arg, dynamic other) {
Avoid using the 'dynamic' type
14
15Future<dynamic> asyncMethod() {
Avoid using the 'dynamic' type
18
19dynamic returnDynamic() {
Avoid using the 'dynamic' type
23class TestClass {
24 dynamic field;
Avoid using the 'dynamic' type
25
26 void method(dynamic param) {
Avoid using the 'dynamic' type
26 void method(dynamic param) {
27 final dynamic local = param;
Avoid using the 'dynamic' type
33// direct `Map<_, dynamic>` argument is.
34List<dynamic> listOfDynamic = [];
Avoid using the 'dynamic' type
35
36Route<dynamic>? routeField;
Avoid using the 'dynamic' type
37
38Map<String, List<dynamic>> nested = {};

Valid

example.dartdart
// Good cases for avoid-dynamic rule
// No violations expected

void testTypedVariable() {
  int x = 5;
  String name = "test";
  List<int> list = [1, 2, 3];
}

void testTypedParameters(int arg, String other) {
  print(arg);
  print(other);
}

Future<int> asyncMethod() {
  return Future.value(42);
}

String returnString() {
  return "anything";
}

class TestClass {
  Object field = Object();

  void method(Object param) {
    final Object local = param;
  }
}

Map<String, int> mapWithType = {};

List<String> listOfString = [];

void testWithGenerics<T>(T value) {
  print(value);
}

void testWithUnion(Object? nullable) {
  if (nullable != null) {
    print(nullable);
  }
}

// dcl exempts `dynamic` used directly as a `Map` type argument (the JSON escape
// hatch) — both in a `Map<...>` annotation and in a `<...>{}` map literal.
Map<String, dynamic> jsonField = {};

Map<String, dynamic> parseJson(Map<String, dynamic> json) {
  final literal = <String, dynamic>{'k': 1};
  return literal;
}

class Serializable {
  Map<String, dynamic> toJson() => <String, dynamic>{};
}

How to configure

Set the severity of avoid-dynamic in your falcon.json:

falcon.jsonjson
{
  "linter": {
    "rules": {
      "suspicious": {
        "avoid-dynamic": "error"
      }
    }
  }
}