Skip to content

list_all_equatable_fields

v0.4.0 Warning Fix Collection & Type

Flags a class extending Equatable or mixing in EquatableMixin whose props getter omits one of its own instance fields. The diagnostic names the missing fields, and the quick fix adds them.

A field added after the fact, with props left as it was. The class still compiles, and two objects that differ only in unreadCount now compare equal:

import 'package:equatable/equatable.dart';
class InboxState extends Equatable {
const InboxState(this.messages, this.unreadCount);
final List<String> messages;
final int unreadCount;
@override
List<Object?> get props => [messages];
}

This is worse than a plain bug in a state class: a state-management layer that skips rebuilds when the old and new state are equal will now skip the rebuild that was supposed to show the new badge.

import 'package:equatable/equatable.dart';
class InboxState extends Equatable {
const InboxState(this.messages, this.unreadCount);
final List<String> messages;
final int unreadCount;
@override
List<Object?> get props => [messages, unreadCount];
}
import 'package:equatable/equatable.dart';
// Don't
class Session with EquatableMixin {
Session(this.userId, this.expiresAt);
final String userId;
final DateTime expiresAt;
@override
List<Object?> get props => [userId];
}
import 'package:equatable/equatable.dart';
// Do
class Session with EquatableMixin {
Session(this.userId, this.expiresAt);
final String userId;
final DateTime expiresAt;
@override
List<Object?> get props => [userId, expiresAt];
}

Only the class’s own instance fields are required. A static const is shared, not per-instance, so it is never expected in props:

import 'package:equatable/equatable.dart';
// No warning
class Username extends Equatable {
const Username(this.value);
final String value;
static const maxLength = 100;
@override
List<Object?> get props => [value];
}

Only fields declared on the class itself are checked. Inherited fields are the parent’s business, and it lists them in its own props.

props must return a list literal directly. A getter that delegates — => _buildProps() — cannot be read statically, and the class is skipped entirely. A literal containing a spread (=> [...super.props, name]) is still read.

Names are matched as identifiers anywhere inside the literal, not as bare entries. props => [name.toLowerCase()] counts as listing name, so a field that only appears inside an expression satisfies the check.

See also: equatable package

This rule is in no preset, so it is off unless you enable it by name:

many_lints.yaml
rules:
list_all_equatable_fields: true

To turn it off again:

many_lints.yaml
rules:
list_all_equatable_fields: false

To keep the rule on but skip certain paths, use per-rule exclude.