avoid-dynamic
Same as avoid-dynamic in Dart Code Metrics
- Group
- Suspicious
- Path
lint/suspicious/avoid-dynamic- Default
- Off, opt in
- Origin
- Dart Code Metrics
- Rule
- 56 of 512
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.
All explicit type positions are checked, including record fields, type
aliases, generic bounds, patterns, and types inside initializers.
Invalid
// 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 = {};
typedef DynamicAlias = List<dynamic>;
(dynamic, {dynamic value}) recordTypes;
class DynamicInitializers {
final values = <dynamic>[];
DynamicInitializers() {
final local = <dynamic>[];
}
set value(Object value) {
dynamic local = value;
}
Object operator +(Object other) {
dynamic local = other;
return local;
}
}
void dynamicSwitch(Object input) {
switch (input) {
default:
dynamic local = input;
}
}
typedef BoundedFunction = void Function<T extends List<dynamic>>();
void dynamicPatterns(Object input) {
if (input case List<dynamic> values) {
print(values);
}
final values = [
for (List<dynamic> value in <List<Object>>[]) value,
];
}
class DynamicBase extends Base<List<dynamic>> {}
@Annotation<List<dynamic>>()
void annotatedDynamic() {}
Object dynamicSwitchExpression(Object input) => switch (input) {
List<dynamic> values => values,
_ => input,
};void testDynamicVariable() { dynamic x = 5; dynamic x = 5; dynamic name = "test"; dynamic name = "test"; dynamic list = [1, 2, 3]; void testDynamicParameters(dynamic arg, dynamic other) { void testDynamicParameters(dynamic arg, dynamic other) { Future<dynamic> asyncMethod() { dynamic returnDynamic() {class TestClass { dynamic field; void method(dynamic param) { void method(dynamic param) { final dynamic local = param;// direct `Map<_, dynamic>` argument is.List<dynamic> listOfDynamic = []; Route<dynamic>? routeField; Map<String, List<dynamic>> nested = {}; typedef DynamicAlias = List<dynamic>; (dynamic, {dynamic value}) recordTypes; (dynamic, {dynamic value}) recordTypes;class DynamicInitializers { final values = <dynamic>[]; DynamicInitializers() { final local = <dynamic>[]; set value(Object value) { dynamic local = value; Object operator +(Object other) { dynamic local = other; default: dynamic local = input; typedef BoundedFunction = void Function<T extends List<dynamic>>();void dynamicPatterns(Object input) { if (input case List<dynamic> values) { final values = [ for (List<dynamic> value in <List<Object>>[]) value, class DynamicBase extends Base<List<dynamic>> {} @Annotation<List<dynamic>>()Object dynamicSwitchExpression(Object input) => switch (input) { List<dynamic> values => values,Valid
import 'dart:core' as core;
// 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>{};
}
void mapConstructorArguments(Object value) {
final empty = Map<String, dynamic>();
final copied = Map<String, dynamic>.from({});
if (value case <String, dynamic>{'key': var item}) {
print(item);
}
}
void prefixedMapConstructorArguments() {
final empty = core.Map<String, dynamic>();
final copied = core.Map<String, dynamic>.from({});
}Configure avoid-dynamic
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"suspicious": {
"avoid-dynamic": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/suspicious/avoid-dynamic: <reason>More suspicious rules
- avoid-empty-else
avoid_empty_elserecommendedFlags an
elseclause whose body is an empty statement (else ;). - avoid-ignoring-return-values
avoid-ignoring-return-valuesFlags a discarded call whose resolved return type is non-void.
- avoid-incorrect-uri
Reject runtime-invalid Uri constructor arguments: conflicting path or query inputs and query parameter values that are neither null, strings nor iterables of strings.
- avoid-inverted-boolean-checks
Prefer direct equality comparisons and De Morgan forms in control-flow conditions.
- avoid-multi-assignment
Split chained assignments into separate statements.
- avoid-mutating-parameters
Detects writes through named function, method and constructor parameter objects.
- avoid-negated-conditions
Prefer positive conditions when both branches can be swapped.
- avoid-nested-assignments
Require assignments to be standalone statements, arrow bodies or loop operations.