Best way to have a const factory for empty instance in Flutter's freezed

1.4k Views Asked by At

I am trying to figure out the best way to implement a constant factory for "empty" instance of the defined model while keeping its original constructor strict (require all arguments without defaults).

The closest solution I could get is using Union types and Sealed classes with an identical set of parameters.

const factory Costs({
  required bool valid,
  required String names,
  required String prices,
  required String subtotal,
  required String deposit,
  required String deliveryCosts,
  required String total,
  String? errCode,
}) = LoadedCosts;

const factory Costs.empty({
  @Default(false) bool valid,
  @Default('') String names,
  @Default('') String prices,
  @Default('') String subtotal,
  @Default('') String deposit,
  @Default('') String deliveryCosts,
  @Default('') String total,
  String? errCode,
}) = EmptyCosts;

So, this will keep my main factory strict, while allowing getting an empty instance via the second one. Important to notice, I also don't have to match sealed classes within the business logic code (all params are identical in both classes, so I can just access fields directly).

The are 2 points of concern:

  • This is still not very lean. I have to redefine all params and prepend @Default decorator.
  • You can use empty factory and still pass custom values, which ideally I would like to avoid. I would like an empty constructor not accepting any arguments.

Ideally, I would expect it to look something like this:

  const Costs.empty()
  : valid = false,
    names = '',
    prices = '',
    subtotal = '',
    deposit = '',
    deliveryCosts = '',
    total = '',
    errCode = null;

This actually works if you are not using freezed. With freezed, however, I need to redirect the constructor, which starts all the problems.

Any thoughts?

1

There are 1 best solutions below

3
On BEST ANSWER

you could actually do this.

@freezed
class Costs with _$Costs {
  const factory Costs({
    required bool valid,
    required String names,
    required String prices,
    required String subtotal,
    required String deposit,
    required String deliveryCosts,
    required String total,
    String? errCode,
  }) = LoadedCosts;

  factory Costs.empty() => const LoadedCosts(
        deliveryCosts: '',
        deposit: '',
        names: '',
        prices: '',
        subtotal: '',
        total: '',
        valid: false,
      );
}

Or else, if you want to pass the instance as a default value in a constructor, you could have a static const variable. Since it is const and immutable we cannot change the state of this static instance. Also anyway if we want to change the state in immutable freezed object, we use .copyWith() which obviously provides new instance without changing existing instance state. So i think this could help.

@freezed
class Costs with _$Costs {
  const factory Costs({
    required bool valid,
    required String names,
    required String prices,
    required String subtotal,
    required String deposit,
    required String deliveryCosts,
    required String total,
    String? errCode,
  }) = LoadedCosts;

  static const emptyCosts = LoadedCosts(
    deliveryCosts: '',
    deposit: '',
    names: '',
    prices: '',
    subtotal: '',
    total: '',
    valid: false,
  );
}

Hope it helps! Happy coding:)