avoid-unnecessary-type-casts

Same as avoid-unnecessary-type-casts in Dart Code Metrics

Path
lint/complexity/avoid-unnecessary-type-casts
Default
On (recommended)
Origin
Dart Code Metrics
Rule
176 of 512
recommended

Flags an as cast to the operand's resolved static type.

Invalid

example.dartdart
// Test cases for avoid-unnecessary-type-casts rule
// Flags 'as T' casts where the variable is already T

void testCastExplicitIntType() {
  final int x = 5;
  final y = x as int;
}

void testCastExplicitStringType() {
  final String name = "hello";
  final result = name as String;
}

void testCastExplicitListType() {
  final List<String> items = [];
  final casted = items as List<String>;
}

void testMultipleUnnecessaryCasts() {
  final bool active = true;
  final double value = 3.14;

  final a = active as bool;
  final b = value as double;
}

class MyClass {
  final int id = 42;

  void castId() {
    final casted = id as int;
    print(casted);
  }
}

void testInlineUnnecessaryCast() {
  final String message = "test";
  final length = (message as String).length;
}

void testChainedUnnecessaryCast() {
  final Map<String, int> data = {};
  final result = data as Map<String, int>;
}

// Regression: the cast must still be found inside Dart 3 containers.
void testCastsInContainers() {
  final int n = 5;
  final (a, _) = (n as int, 0);
  lbl: {
    final b = n as int;
    print(b);
  }
  final c = switch (n) {
    0 => n as int,
    _ => 0,
  };
  final d = switch (n as int) {
    _ => 0,
  };
  final e = [if (n > 0) n as int];
  final f = [...[n as int]];
  final g = (p: n as int, q: 0);
  print([a, c, d, e, f, g]);
}

// Regression: locals declared inside a loop or a try body are tracked, so a
// redundant cast there is still reported.
void loopScopeRegression(List<int> xs) {
  for (final _ in xs) {
    final int inLoop = 1;
    print(inLoop as int);
  }
  try {
    final int inTry = 2;
    print(inTry as int);
  } catch (e) {
    print(e);
  }
}

void typedCollectionForCastRegression() {
  final list = [
    for (int i = 0; i < 2; i++) i as int,
  ];
  final map = {
    for (int j = 0; j < 2; j++) j: j as int,
  };
  print([list, map]);
}

// Initializing an `int?` local with an `int` promotes it to `int`; Dart 3.13.5
// `dart analyze` reports unnecessary_cast here.
void testCastPromotedOnInitialization() {
  int? maybeInt = 5;
  final int nonNull = maybeInt as int;
  print(nonNull);
}
Remove this type cast because the variable is already known to have this type.
5 final int x = 5;
6 final y = x as int;
Remove this type cast because the variable is already known to have this type.
10 final String name = "hello";
11 final result = name as String;
Remove this type cast because the variable is already known to have this type.
15 final List<String> items = [];
16 final casted = items as List<String>;
Remove this type cast because the variable is already known to have this type.
22
23 final a = active as bool;
Remove this type cast because the variable is already known to have this type.
23 final a = active as bool;
24 final b = value as double;
Remove this type cast because the variable is already known to have this type.
30 void castId() {
31 final casted = id as int;
Remove this type cast because the variable is already known to have this type.
37 final String message = "test";
38 final length = (message as String).length;
Remove this type cast because the variable is already known to have this type.
42 final Map<String, int> data = {};
43 final result = data as Map<String, int>;
Remove this type cast because the variable is already known to have this type.
48 final int n = 5;
49 final (a, _) = (n as int, 0);
Remove this type cast because the variable is already known to have this type.
50 lbl: {
51 final b = n as int;
Remove this type cast because the variable is already known to have this type.
54 final c = switch (n) {
55 0 => n as int,
Remove this type cast because the variable is already known to have this type.
57 };
58 final d = switch (n as int) {
Remove this type cast because the variable is already known to have this type.
60 };
61 final e = [if (n > 0) n as int];
Remove this type cast because the variable is already known to have this type.
61 final e = [if (n > 0) n as int];
62 final f = [...[n as int]];
Remove this type cast because the variable is already known to have this type.
62 final f = [...[n as int]];
63 final g = (p: n as int, q: 0);
Remove this type cast because the variable is already known to have this type.
71 final int inLoop = 1;
72 print(inLoop as int);
Remove this type cast because the variable is already known to have this type.
75 final int inTry = 2;
76 print(inTry as int);
Remove this type cast because the variable is already known to have this type.
83 final list = [
84 for (int i = 0; i < 2; i++) i as int,
Remove this type cast because the variable is already known to have this type.
86 final map = {
87 for (int j = 0; j < 2; j++) j: j as int,
Remove this type cast because the variable is already known to have this type.
95 int? maybeInt = 5;
96 final int nonNull = maybeInt as int;

Valid

example.dartdart
// Good examples for avoid-unnecessary-type-casts rule
// Type casts where the variable is not already known to be T

void testCastDynamicToInt() {
  dynamic value = 42;
  final int x = value as int;
}

void testCastObjectToString() {
  Object obj = "hello";
  final String name = obj as String;
}

void testCastFromParameter() {
  void process(dynamic param) {
    final int x = param as int;
    print(x);
  }
}

void testCastNullableToNonNullable() {
  int? maybeInt = int.tryParse('5');
  final int nonNull = maybeInt as int;
}

void testCastBroadToNarrow() {
  List<dynamic> items = [1, 2, 3];
  final List<int> ints = items as List<int>;
}

void testCastBetweenUnrelatedTypes() {
  Object shape = Circle();
  final Circle c = shape as Circle;
}

void testCastFromJsonDecode() {
  dynamic json = {"id": 42};
  final Map<String, dynamic> data = json as Map<String, dynamic>;
}

class Circle {}

Configure avoid-unnecessary-type-casts

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "complexity": {
        "avoid-unnecessary-type-casts": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/complexity/avoid-unnecessary-type-casts: <reason>
  • cascade-invocationscascade_invocations

    Flags consecutive statements that invoke members on the same variable.

  • cognitive-complexity

    Reports function bodies with excessive nesting-weighted control flow.

  • cyclomatic-complexitycyclomatic_complexity

    Flags a function whose cyclomatic complexity exceeds the configured threshold.

  • join-return-with-assignmentjoin_return_with_assignment

    Flags an assignment immediately followed by return of the same variable.

  • max-lines-for-filemax_lines_for_file

    Flags a file longer than the configured line limit.

  • max-lines-for-functionmax_lines_for_function

    Flags a function or method longer than the configured line limit.

  • max-parameters-for-functionmax_parameters_for_function

    Flags callable declarations and function types with more than the configured number of parameters.

  • max-statements

    Reports function bodies with too many statements.