use-enums

Same as use_enums in Dart lints

Group
Style
Path
lint/style/use-enums
Default
Off, opt in
Origin
Dart lints
Rule
487 of 512

Flags classes that emulate an enum and could be declared as one.

Before enhanced enums (Dart 2.17), a fixed set of values with fields and methods was modeled as a class with private const constructors and static const instances. An enum now expresses the same thing with exhaustiveness checking, values, index, and name for free.

class LogPriority {           // flagged
  static const error = LogPriority._(1, 'Error');
  static const warning = LogPriority._(2, 'Warning');
  final int priority;
  final String prefix;
  const LogPriority._(this.priority, this.prefix);
}

A class qualifies when it is concrete, extends only Object, declares no ==, hashCode, index, or values member, has only const or factory constructors (all private if the class is public), and has two or more static const fields initialized by its own generative constructor. It is disqualified when the file subclasses, implements, or mixes it in, or invokes a generative constructor anywhere other than those initializers.

Invalid

example.dartdart
class LogPriority {
  static const error = LogPriority._(1, 'Error');
  static const warning = LogPriority._(2, 'Warning');
  static const log = LogPriority._unknown('Log');

  final String prefix;
  final int priority;
  const LogPriority._(this.priority, this.prefix);
  const LogPriority._unknown(String prefix) : this._(-1, prefix);
}

// Private classes may use a public constructor.
class _Direction {
  static const north = _Direction(0);
  static const south = _Direction(180);
  final int degrees;
  const _Direction(this.degrees);
}

// A private factory constructor does not disqualify the class.
class Suit {
  static const hearts = Suit._('h');
  static const spades = Suit._('s');
  final String code;
  const Suit._(this.code);
  factory Suit._parse(String code) => code == 'h' ? hearts : spades;
  static Suit parse(String code) => Suit._parse(code);
}

// `new`-style creation and `extends Object` are fine.
class Planet extends Object {
  static const mercury = const Planet._(0.38);
  static const venus = const Planet._(0.91);
  final double gravity;
  const Planet._(this.gravity);
  double weight(double mass) => mass * gravity;
}

// Other members are allowed alongside the constants.
class Status {
  static const active = Status._('active');
  static const inactive = Status._('inactive');
  static const all = [active, inactive];
  final String label;
  const Status._(this.label);
  @override
  String toString() => label;
}

// Explicit constructor type arguments still create instances of this class.
class _GenericChoice<T> {
  static const first = _GenericChoice<int>._(0);
  static const second = _GenericChoice<int>._(1);
  final int value;
  const _GenericChoice._(this.value);
}

final genericChoice = _GenericChoice.first;
Class should be an enum.
1class LogPriority {
Class should be an enum.
12// Private classes may use a public constructor.
13class _Direction {
Class should be an enum.
20// A private factory constructor does not disqualify the class.
21class Suit {
Class should be an enum.
30// `new`-style creation and `extends Object` are fine.
31class Planet extends Object {
Class should be an enum.
39// Other members are allowed alongside the constants.
40class Status {
Class should be an enum.
50// Explicit constructor type arguments still create instances of this class.
51class _GenericChoice<T> {

Valid

example.dartdart
enum LogPriority {
  error(1, 'Error'),
  warning(2, 'Warning');

  final int priority;
  final String prefix;
  const LogPriority(this.priority, this.prefix);
}

// Only one constant.
class Single {
  static const only = Single._();
  const Single._();
}

// Public constructor on a public class.
class Open {
  static const a = Open(1);
  static const b = Open(2);
  final int v;
  const Open(this.v);
}

// Abstract classes are skipped.
abstract class Shape {
  static const circle = _Circle();
  static const square = _Circle();
  const Shape();
}

class _Circle extends Shape {
  const _Circle();
}

// Overrides `==` / `hashCode`.
class Coin {
  static const heads = Coin._(0);
  static const tails = Coin._(1);
  final int side;
  const Coin._(this.side);
  @override
  bool operator ==(Object other) => other is Coin && other.side == side;
  @override
  int get hashCode => side;
}

// Declares `index` or `values`.
class Indexed {
  static const first = Indexed._(0);
  static const second = Indexed._(1);
  final int index;
  const Indexed._(this.index);
}

// Subclassed in the library.
class Animal {
  static const cat = Animal._();
  static const dog = Animal._();
  const Animal._();
}

class Pet extends Animal {
  const Pet() : super._();
}

// Constructor invoked outside the constants.
class Level {
  static const low = Level._(0);
  static const high = Level._(1);
  final int value;
  const Level._(this.value);
}

Level custom(int v) => Level._(v);

// Non-const generative constructor.
class Mutable {
  static final a = Mutable._();
  static final b = Mutable._();
  Mutable._();
}

// Extends another class.
class Base {
  const Base();
}

class Derived extends Base {
  static const x = Derived._();
  static const y = Derived._();
  const Derived._();
}

// A public factory constructor on a public class.
class Suit {
  static const hearts = Suit._('h');
  static const spades = Suit._('s');
  final String code;
  const Suit._(this.code);
  factory Suit.parse(String code) => code == 'h' ? hearts : spades;
}

// An explicit generic constructor invocation outside the constants is a use.
class _GenericChoice<T> {
  static const first = _GenericChoice<int>._(0);
  static const second = _GenericChoice<int>._(1);
  final int value;
  const _GenericChoice._(this.value);
}

_GenericChoice<int> customGenericChoice(int value) => _GenericChoice<int>._(value);

Configure use-enums

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

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "use-enums": "error"
      }
    }
  }
}

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

example.dartdart
// falcon-ignore lint/style/use-enums: <reason>
  • use-existing-destructuring

    Reuse or extend an existing record destructuring instead of rereading a field.

  • use-existing-variable

    Reuse a local for stable SDK arithmetic and String.length/int parity getters.

  • use-full-hex-values-for-flutter-colorsuse_full_hex_values_for_flutter_colorsrecommendedflutter

    Require an eight-digit hexadecimal integer for the canonical Flutter Color default constructor.

  • use-function-type-syntax-for-parametersuse_function_type_syntax_for_parametersrecommended

    Flags an old-style function-typed parameter written with inline parameter syntax.

  • use-if-null-to-convert-nulls-to-boolsuse_if_null_to_convert_nulls_to_boolsrecommended

    Prefers ?? to comparing a nullable bool against a boolean literal.

  • use-late-for-private-fields-and-variablesuse_late_for_private_fields_and_variables

    Flags a private nullable field or top-level variable that is only ever assigned non-null values and read through !, so it could be late with a non-nullable type.

  • use-named-constantsuse_named_constantsrecommended

    Prefers a class's predefined static constant to constructing an equal constant.

  • use-raw-stringsuse_raw_strings

    Flags string literals whose only escapes are \\ and \$, which a raw string would express without any backslash.