avoid_collection_methods_with_unrelated_types
Flags contains, remove, lookup, containsKey, containsValue and map indexing called with an argument whose type is unrelated to the collection’s element or key type. These methods take Object?, so the compiler accepts the call — and it silently answers false, null or nothing at all.
The usual cause is an id whose type changed. The lookup compiles, returns false forever, and the feature quietly stops working:
bool isSelected(List<int> selectedIds, String id) { return selectedIds.contains(id);}Convert at the boundary so the types line up:
bool isSelected(List<int> selectedIds, String id) { final parsed = int.tryParse(id); return parsed != null && selectedIds.contains(parsed);}Map keys and values
Section titled “Map keys and values”containsKey and remove are checked against the key type, containsValue against the value type:
// Don'tfinal labels = <int, String>{1: 'One'};
labels.containsKey('1'); // key type is intlabels.containsValue(42); // value type is Stringlabels.remove('1');// Dofinal labels = <int, String>{1: 'One'};
labels.containsKey(1);labels.containsValue('One');labels.remove(1);Indexing a map is checked the same way, which catches the commonest form of the mistake:
// Don'tfinal label = labels['1']; // always null
// Dofinal label = labels[1];Subtypes are fine
Section titled “Subtypes are fine”Relatedness runs in both directions, so a subtype argument is accepted:
final measurements = <num>[1, 2, 3];
measurements.contains(42); // int is a num — acceptedmeasurements.contains(1.5); // double is a num — acceptedReporting dynamic arguments
Section titled “Reporting dynamic arguments”A dynamic argument is not reported by default — its runtime value may well be the right type. Turn strict on in a codebase that has eliminated dynamic and wants the stragglers surfaced:
rules: avoid_collection_methods_with_unrelated_types: strict: truefinal ids = <int>[1, 2, 3];dynamic raw = readFromCache();
// Reported only with strict: trueids.contains(raw);
// Do — narrow before the lookupif (raw is int) { ids.contains(raw);}Known limitations
Section titled “Known limitations”Type parameters are never reported, in strict mode or not: List<T>.contains(value) cannot be judged until T is chosen at the call site.
A dynamic collection tells you nothing. List<dynamic>.contains(anything) is always accepted, since the element type carries no constraint to violate.
Two unrelated classes are compared by hierarchy only. Neither being a subtype of the other is enough to report — unlike avoid_unrelated_type_casts, this rule does not first ask whether a third class could implement both.
Turning this rule off
Section titled “Turning this rule off”This rule is in the core preset, so it is on with preset: core,
preset: recommended or preset: opinionated.
To turn it off:
rules: avoid_collection_methods_with_unrelated_types: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Options
Section titled “Options”many_lints: rules: avoid_collection_methods_with_unrelated_types: strict: truerules: avoid_collection_methods_with_unrelated_types: strict: true| Option | Type | Default | Description |
|---|---|---|---|
strict |
bool | false |
Also report a dynamic argument passed where a known element type is expected |
Related rules
Section titled “Related rules”avoid_unsafe_collection_methods— Check for emptiness before using first, last, single or reduce.avoid_collection_equality_checks— Avoid comparing collections with == or != as it checks reference equality, not contents.avoid_duplicate_collection_elements— Don’t repeat the same element in a collection literal.avoid_unrelated_type_casts— Don’t cast or type-test between unrelated types.