Code generation for immutable classes that has a simple syntax/API without compromising on the features.

Last update: Aug 17, 2022

Build pub package Discord

Welcome to Freezed, yet another code generator for unions/pattern-matching/copy.

0.14.0 and null-safety

Important note:

From 0.14.0 and onwards, Freezed does not support non-null-safe code.

If you want to keep using Freezed but cannot migrate to null-safety yet, use the version 0.12.7 instead.
Note that this version is no-longer maintained (so bugs found there won't be fixed).

For the documentation of the version 0.12.7, refer to https://pub.dev/packages/freezed/versions/0.12.7

In the scenario where you are using the version 0.12.7, but one of your dependency is using 0.14.0 or above, you will have a version conflict on freezed_annotation.

In that case, you can fix the error by adding the following to your pubspec.yaml:

dependency_overrides:
  freezed: ^0.12.7
  freezed_annotation: ^0.12.0

Motivation

If you are familiar with other programming languages, you may have heard about concepts such as data-classes or pattern matching.
These features are excellent at making your codebase more robust and readable.
Sadly, Dart currently does not support those features.

Freezed is designed as a language patch, relying on code-generation to implement those missing features.

Using Freezed, we will get:

  • a simple and concise syntax for defining models, where we don't need to define both a constructor and a property.
    Instead, we only need to define the constructor, removing unnecessary duplication.

  • a copyWith method, for cloning objects with different values.
    Note: As opposed to many alternatives, when using Freezed, that copyWith method correctly supports assigning null to a value.

  • union-types/pattern matching, for making impossible states impossible. See also [#unionssealed-classes].

  • an automatic serialization/deserialization of your objects (including union types).

  • a default ==/toString implementation which respectively compares/shows all properties of the object.

See the example or the index for a preview on what's available

Index

How to use

Install

To use Freezed, you will need your typical build_runner/code-generator setup.
First, install build_runner and Freezed by adding them to your pubspec.yaml file:

# pubspec.yaml
dependencies:
  freezed_annotation:

dev_dependencies:
  build_runner:
  freezed:

This installs three packages:

Disabling invalid_annotation_target warning and warning in generates files.

If you plan on using Freezed in combination with json_serializable, recent versions of json_serializable and meta may require you to disable the invalid_annotation_target warning.

Similarly, you may want to disable warnings that happen in .freezed.dart, if any.

To do that, you can add the following to an analysis_options.yaml at the root of your project:

analyzer:
  exclude:
    - "**/*.g.dart"
    - "**/*.freezed.dart"
  errors:
    invalid_annotation_target: ignore

Run the generator

To run the code generator you have two possibilities:

  • If your package depends on Flutter:
    • flutter pub run build_runner build
  • If your package does not depend on Flutter:
    • dart pub run build_runner build

Note that like most code-generators, Freezed will need you to both import the annotation (meta) and use the part keyword on the top of your files.

As such, a file that wants to use Freezed will start with:

import 'package:freezed_annotation/freezed_annotation.dart';

part 'my_file.freezed.dart';

CONSIDER also importing package:flutter/foundation.dart.
The reason being, importing foundation.dart also imports classes to make an object nicely readable in Flutter's devtool.
If you import foundation.dart, Freezed will automatically do it for you.

A full example would be:

// main.dart
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:flutter/foundation.dart';

part 'main.freezed.dart';

@freezed
class Union with _$Union {
  const factory Union(int value) = Data;
  const factory Union.loading() = Loading;
  const factory Union.error([String? message]) = ErrorDetails;
}

Ignore lint warnings on generated files

It is likely that the code generated by Freezed will cause your linter to report warnings.

The solution to this problem is to tell the linter to ignore generated files, by modifying your analysis_options.yaml:

analyzer:
  exclude:
    - "**/*.g.dart"
    - "**/*.freezed.dart"

The features

The syntax

Basics

Freezed works differently than most generators. To define a class using Freezed, you will not declare properties but instead factory constructors.

For example, if you want to define a Person class, which has 2 properties:

  • name, a String
  • age, an int

To do so, you will have to define a factory constructor that takes these properties as parameter:

@freezed
class Person with _$Person {
  factory Person({ String? name, int? age }) = _Person;
}

Which then allows you to write:

var person = Person(name: 'Remi', age: 24);
print(person.name); // Remi
print(person.age); // 24

NOTE:
You do not have to use named parameters for your constructor.

All valid parameter syntaxes are supported. As such you could write:

@freezed
class Person with _$Person {
  factory Person(String name, int age) = _Person;
}

Person('Remi', 24)
@freezed
class Person with _$Person {
  const factory Person(String name, {int? age}) = _Person;
}

Person('Remi', age: 24)

...

You are also not limited to one constructor and non-generic class.
From example, you should write:

@freezed
class Union<T> with _$Union<T> {
  const factory Union(T value) = Data<T>;
  const factory Union.loading() = Loading<T>;
  const factory Union.error([String? message]) = ErrorDetails<T>;
}

See unions/Sealed classes for more information.

The abstract keyword

As you might have noticed, the abstract keyword is not needed anymore when declaring freezed classes.

This allows you to easily use mixins with the benefit of having your IDE telling you what to implement.

We can now turn this:

@freezed
abstract class MixedIn with Mixin implements _$MixedIn {
  MixedIn._();
  factory MixedIn() = _MixedIn;
}

mixin Mixin {
  int method() => 42;
}

into this:

@freezed
class MixedIn with _$MixedIn, Mixin {
  const MixedIn._();
  factory MixedIn() = _MixedIn;
}

mixin Mixin {
  int method() => 42;
}

Custom getters and methods

Sometimes, you may want to manually define methods/properties on that class.

But you will quickly notice that if you try to do:

@freezed
class Person with _$Person {
  const factory Person(String name, {int? age}) = _Person;

  void method() {
    print('hello world');
  }
}

then it won't work.

This is because by default, Freezed has no way of "extending" the class and instead "implements" it.

To fix it, we need a subtle syntax change to allow Freezed to generate valid code.
To do so, we have to define a single private constructor:

@freezed
class Person with _$Person {
  const Person._(); // Added constructor
  const factory Person(String name, {int? age}) = _Person;

  void method() {
    print('hello world');
  }
}

Asserts

A common use-case with classes is to want to add assert(...) statements to a construtor:

class Person {
  Person({
    String? name,
    int? age,
  })  : assert(name.isNotEmpty, 'name cannot be empty'),
        assert(age >= 0);

  final String name;
  final int age;
}

Freezed supports this use-case through the @Assert decorator:

abstract class Person with _$Person {
  @Assert('name.isNotEmpty', 'name cannot be empty')
  @Assert('age >= 0')
  factory Person({
    String? name,
    int? age,
  }) = _Person;
}

Default values

Unfortunately, Dart does not allow constructors with the syntax used by Freezed to specify default values.

Which means you cannot write:

abstract class Example with _$Example {
  const factory Example([int value = 42]) = _Example;
}

But Freezed offers an alternative for this: @Default
As such, you could rewrite the previous snippet this way:

abstract class Example with _$Example {
  const factory Example([@Default(42) int value]) = _Example;
}

NOTE:
If you are using serialization/deserialization, this will automatically add a @JsonKey(defaultValue: <something>) for you.

Constructor tear-off

A common use-case is to do a one-to-one mapping between the parameters of a callback and a constructor.
For example, you may write:

future.catchError((error) => MyClass.error(error))

But that's kind of redundant. As such, Freezed offers a simpler syntax:

future.catchError($MyClass.error)

This new code is strictly equivalent to the previous snippet, just shorter.

Note that this is both compatible with default values and generics.

Decorators and comments

Freezed supports property and class level decorators/documentation by decorating/documenting their respective parameter and constructor definition.

Consider:

@freezed
class Person with _$Person {
  const factory Person({
    String? name,
    int? age,
    Gender? gender,
  }) = _Person;
}

If you want to document name, you can do:

@freezed
class Person with _$Person {
  const factory Person({
    /// The name of the user.
    ///
    /// Must not be null
    String? name,
    int? age,
    Gender? gender,
  }) = _Person;
}

If you want to mark the property gender as @deprecated, then you can do:

@freezed
class Person with _$Person {
  const factory Person({
    String? name,
    int? age,
    @deprecated Gender? gender,
  }) = _Person;
}

This will deprecate both:

  • The constructor
    Person(gender: Gender.something); // gender is deprecated
  • The generated class's constructor:
    _Person(gender: Gender.something); // gender is deprecated
  • the property:
    Person person;
    print(person.gender); // gender is deprecated
  • the copyWith parameter:
    Person person;
    person.copyWith(gender: Gender.something); // gender is deprecated

Similarly, if you want to decorate the generated class you can decorate the defining factory constructor.

As such, to deprecate _Person, you could do:

@freezed
class Person with _$Person {
  @deprecated
  const factory Person({
    String? name,
    int? age,
    Gender? gender,
  }) = _Person;
}

Mixins and Interfaces for individual classes for union types

When you have multiple types in the same class you might want to make one of those types to implement a interface or mixin a class. You can do that using the @Implements decorator or @With respectively. In this case City is implementing with GeographicArea.

abstract class GeographicArea {
  int get population;
  String get name;
}

@freezed
class Example with _$Example {
  const factory Example.person(String name, int age) = Person;

  @Implements<GeographicArea>()
  const factory Example.city(String name, int population) = City;
}

In case you want to specify a generic mixin or interface you need to declare it as a string using the With.fromString constructor, Implements.fromString respectively. Similar Street is mixing with AdministrativeArea<House>.

abstract class GeographicArea {}
abstract class House {}
abstract class Shop {}
abstract class AdministrativeArea<T> {}

@freezed
class Example with _$Example {
  const factory Example.person(String name, int age) = Person;

  @With<AdministrativeArea<House>>()
  const factory Example.street(String name) = Street;

  @With<House>()
  @Implements<Shop>()
  @Implements<GeographicArea>()
  const factory Example.city(String name, int population) = City;
}

Note: You need to make sure that you comply with the interface requirements by implementing all the abstract members. If the interface has no members or just fields, you can fulfil the interface contract by adding them in the constructor of the union type. Keep in mind that if the interface defines a method or a getter, that you implement in the class, you need to use the Custom getters and methods instructions.

Note 2: You cannot use @With/@Implements with freezed classes. Freezed classes can neither be extended nor implemented.

==/toString

When using Freezed, the toString, hashCode and == methods are overridden as you would expect:

@freezed
class Person with _$Person {
  factory Person({ String? name, int? age }) = _Person;
}


void main() {
  print(Person(name: 'Remi', age: 24)); // Person(name: Remi, age: 24)

  print(
    Person(name: 'Remi', age: 24) == Person(name: 'Remi', age: 24),
  ); // true
}

copyWith

As stated in the very beginning of this readme, Freezed does not compromise on the syntax to have a powerful copy.

The copyWith method generated by Freezed does support assigning a value to null.
For example, if we take our previous Person class:

@freezed
class Person with _$Person {
  factory Person(String name, int age) = _Person;
}

Then we could write:

var person = Person('Remi', 24);

// `age` not passed, its value is preserved
print(person.copyWith(name: 'Dash')); // Person(name: Dash, age: 24)
// `age` is set to `null`
print(person.copyWith(age: null)); // Person(name: Remi, age: null)

Notice how copyWith correctly was able to understand null parameters.

Deep copy

While copyWith is very powerful in itself, it starts to get inconvenient on more complex objects.

Consider the following classes:

@freezed
class Company with _$Company {
  factory Company({String? name, Director? director}) = _Company;
}

@freezed
class Director with _$Director {
  factory Director({String? name, Assistant? assistant}) = _Director;
}

@freezed
class Assistant with _$Assistant {
  factory Assistant({String? name, int? age}) = _Assistant;
}

Then, from a reference on Company, we may want to perform changes on Assistant.
For example, to change the name of an assistant, using copyWith we would have to write:

Company company;

Company newCompany = company.copyWith(
  director: company.director.copyWith(
    assistant: company.director.assistant.copyWith(
      name: 'John Smith',
    ),
  ),
);

This works, but is relatively verbose with a lot of duplicates.
This is where we could use Freezed's "deep copy".

If an object decorated using @freezed contains other objects decorated with @freezed, then Freezed will offer an alternate syntax to the previous example:

Company company;

Company newCompany = company.copyWith.director.assistant(name: 'John Smith');

This snippet will achieve strictly the same result as the previous snippet (creating a new company with an updated assistant name), but no longer has duplicates.

Going deeper in this syntax, if instead, we wanted to change the director's name then we could write:

Company company;
Company newCompany = company.copyWith.director(name: 'John Doe');

Overall, based on the definitions of Company/Director/Assistant mentioned above, all the following "copy" syntaxes will work:

Company company;

company = company.copyWith(name: 'Google', director: Director(...));
company = company.copyWith.director(name: 'Larry', assistant: Assistant(...));
company = company.copyWith.director.assistant(name: 'John', age: 42);

Null consideration

Some objects may also be null. For example, using our Company class, then Director may be null.

As such, writing:

Company company = Company(name: 'Google', director: null);
Company newCompany = company.copyWith.director.assistant(name: 'John');

doesn't make sense.
We can't change the director's assistant if there is no director to begin with.\

In that situation, company.copyWith.director will return null, and our previous example will result in a null exception.

To fix it, we can use the ?. operator and write:

Company? newCompany = company.copyWith.director?.assistant(name: 'John');

Unions/Sealed classes

Coming from other languages, you may be used with features like "tagged union types" / sealed classes/pattern matching.
These are powerful tools in combination with a type system, but Dart currently does not support them.

But fear not, Freezed supports them all, by using a syntax similar to Kotlin.

Defining a union/sealed class with Freezed is simple: write multiple constructors:

@freezed
class Union with _$Union {
  const factory Union(int value) = Data;
  const factory Union.loading() = Loading;
  const factory Union.error([String? message]) = ErrorDetails;
}

This snippet defines a class with three states.
Note how we gave meaningful names to the right hand of the factory constructors we defined. They will come in handy later.

Shared properties

When defining multiple constructors, you will lose the ability to read properties that are not common to all constructors:

For example, if you write:

@freezed
class Example with _$Example {
  const factory Example.person(String name, int age) = Person;
  const factory Example.city(String name, int population) = City;
}

Then you will be unable to read age and population directly:

var example = Example.person('Remi', 24);
print(example.age); // does not compile!

On the other hand, you can read properties that are defined on all constructors.
For example, the name variable is common to both Example.person and Example.city constructors.

As such we can write:

var example = Example.person('Remi', 24);
print(example.name); // Remi
example = Example.city('London', 8900000);
print(example.name); // London

You also can use copyWith with properties defined on all constructors:

var example = Example.person('Remi', 24);
print(example.copyWith(name: 'Dash')); // Example.person(name: Dash, age: 24)

example = Example.city('London', 8900000);
print(example.copyWith(name: 'Paris')); // Example.city(name: Paris, population: 8900000)

To be able to read the other properties, you can use pattern matching thanks to the generated methods:

Alternatively, you can use the is operator:

var example = Example.person('Remi', 24);
if (example is Person) {
  print(example.age); // 24
}

When

The when method is the equivalent to pattern matching with destructing.
Its prototype depends on the constructors defined.

For example, with:

@freezed
class Union with _$Union {
  const factory Union(int value) = Data;
  const factory Union.loading() = Loading;
  const factory Union.error([String? message]) = ErrorDetails;
}

Then when will be:

var union = Union(42);

print(
  union.when(
    (int value) => 'Data $data',
    loading: () => 'loading',
    error: (String? message) => 'Error: $message',
  ),
); // Data 42

Whereas if we defined:

@freezed
class Model with _$Model {
  factory Model.first(String a) = First;
  factory Model.second(int b, bool c) = Second;
}

Then when will be:

var model = Model.first('42');

print(
  model.when(
    first: (String a) => 'first $a',
    second: (int b, bool c) => 'second $b $c'
  ),
); // first 42

Notice how each callback matches with a constructor's name and prototype.

NOTE:
All callbacks are required and must not be null.
If that is not what you want, consider using maybeWhen.

MaybeWhen

The maybeWhen method is equivalent to when, but doesn't require all callbacks to be specified.

On the other hand, it adds an extra orElse required parameter, for fallback behavior.

As such, using:

@freezed
class Union with _$Union {
  const factory Union(int value) = Data;
  const factory Union.loading() = Loading;
  const factory Union.error([String message]) = ErrorDetails;
}

Then we could write:

var union = Union(42);

print(
  union.maybeWhen(
    null, // ignore the default case
    loading: () => 'loading',
    // did not specify an `error` callback
    orElse: () => 'fallback',
  ),
); // fallback

This is equivalent to:

var union = Union(42);

String label;
if (union is Loading) {
  label = 'loading';
} else {
  label = 'fallback';
}

But it is safer as you are forced to handle the fallback case, and it is easier to write.

Map/MaybeMap

The map and maybeMap methods are equivalent to when/maybeWhen, but without destructuring.

Consider this class:

@freezed
class Model with _$Model {
  factory Model.first(String a) = First;
  factory Model.second(int b, bool c) = Second;
}

With such class, while when will be:

var model = Model.first('42');

print(
  model.when(
    first: (String a) => 'first $a',
    second: (int b, bool c) => 'second $b $c'
  ),
); // first 42

map will instead be:

var model = Model.first('42');

print(
  model.map(
    first: (First value) => 'first ${value.a}',
    second: (Second value) => 'second ${value.b} ${value.c}'
  ),
); // first 42

This can be useful if you want to do complex operations, like copyWith/toString for example:

var model = Model.second(42, false)
print(
  model.map(
    first: (value) => value,
    second: (value) => value.copyWith(c: true),
  )
); // Model.second(b: 42, c: true)

FromJson/ToJson

While Freezed will not generate your typical fromJson/toJson by itself, it knowns what json_serializable is.

Making a class compatible with json_serializable is very straightforward.

Consider this snippet:

import 'package:freezed_annotation/freezed_annotation.dart';

part 'model.freezed.dart';

@freezed
class Model with _$Model {
  factory Model.first(String a) = First;
  factory Model.second(int b, bool c) = Second;
}

The changes necessary to make it compatible with json_serializable consists of two lines:

  • a new part: part 'model.g.dart';
  • a new constructor on the targeted class: factory Model.fromJson(Map<String, dynamic> json) => _$ModelFromJson(json);

The end result is:

import 'package:freezed_annotation/freezed_annotation.dart';

part 'model.freezed.dart';
part 'model.g.dart';

@freezed
class Model with _$Model {
  factory Model.first(String a) = First;
  factory Model.second(int b, bool c) = Second;

  factory Model.fromJson(Map<String, dynamic> json) => _$ModelFromJson(json);
}

Don't forget to add json_serializable to your pubspec.yaml:

dev_dependencies:
  json_serializable:

That's it!
With these changes, Freezed will automatically ask json_serializable to generate all the necessary fromJson/toJson.

Note:
Freezed will only generate a fromJson if the factory is using =>.

fromJSON - classes with multiple constructors

For classes with multiple constructors, Freezed will check the JSON response for a string element called runtimeType and choose the constructor to use based on its value. For example, given the following constructors:

@freezed
class MyResponse with _$MyResponse {
  const factory MyResponse(String a) = MyResponseData;
  const factory MyResponse.special(String a, int b) = MyResponseSpecial;
  const factory MyResponse.error(String message) = MyResponseError;

  factory MyResponse.fromJson(Map<String, dynamic> json) => _$MyResponseFromJson(json);
}

Then Freezed will use each JSON object's runtimeType to choose the constructor as follows:

[
  {
    "runtimeType": "default",
    "a": "This JSON object will use constructor MyResponse()"
  },
  {
    "runtimeType": "special",
    "a": "This JSON object will use constructor MyResponse.special()",
    "b": 42
  },
  {
    "runtimeType": "error",
    "message": "This JSON object will use constructor MyResponse.error()"
  }
]

You can customize key and value with something different using @Freezed and @FreezedUnionValue decorators:

@Freezed(unionKey: 'type', unionValueCase: FreezedUnionCase.pascal)
abstract class MyResponse with _$MyResponse {
  const factory MyResponse(String a) = MyResponseData;

  @FreezedUnionValue('SpecialCase')
  const factory MyResponse.special(String a, int b) = MyResponseSpecial;

  const factory MyResponse.error(String message) = MyResponseError;

  // ...
}

which would update the previous json to:

[
  {
    "type": "Default",
    "a": "This JSON object will use constructor MyResponse()"
  },
  {
    "type": "SpecialCase",
    "a": "This JSON object will use constructor MyResponse.special()",
    "b": 42
  },
  {
    "type": "Error",
    "message": "This JSON object will use constructor MyResponse.error()"
  }
]

If you want to customize key and value for all the classes, you can specify it inside your build.yaml file, for example:

targets:
  $default:
    builders:
      freezed:
        options:
          union_key: type
          union_value_case: pascal

If you don't control the JSON response, then you can implement a custom converter. Your custom converter will need to implement its own logic for determining which constructor to use.

class MyResponseConverter implements JsonConverter<MyResponse, Map<String, dynamic>> {
  const MyResponseConverter();

  @override
  MyResponse fromJson(Map<String, dynamic> json) {
    if (json == null) {
      return null;
    }
    // type data was already set (e.g. because we serialized it ourselves)
    if (json['runtimeType'] != null) {
      return MyResponse.fromJson(json);
    }
    // you need to find some condition to know which type it is. e.g. check the presence of some field in the json
    if (isTypeData) {
      return MyResponseData.fromJson(json);
    } else if (isTypeSpecial) {
      return MyResponseSpecial.fromJson(json);
    } else if (isTypeError) {
      return MyResponseError.fromJson(json);
    } else {
      throw Exception('Could not determine the constructor for mapping from JSON');
    }
 }

  @override
  Map<String, dynamic> toJson(MyResponse data) => data.toJson();
}

To then apply your custom converter pass the decorator to a constructor parameter.

@freezed
class MyModel with _$MyModel {
  const factory MyModel(@MyResponseConverter() MyResponse myResponse) = MyModelData;

  factory MyModel.fromJson(Map<String, dynamic> json) => _$MyModelFromJson(json);
}

By doing this, json serializable will use MyResponseConverter.fromJson() and MyResponseConverter.toJson() to convert MyResponse.

You can also use a custom converter on a constructor parameter contained in a List.

@freezed
class MyModel with _$MyModel {
  const factory MyModel(@MyResponseConverter() List<MyResponse> myResponse) = MyModelData;

  factory MyModel.fromJson(Map<String, dynamic> json) => _$MyModelFromJson(json);
}

Note:
In order to serialize nested lists of freezed objects, you are supposed to either specify a @JsonSerializable(explicitToJson: true) or change explicit_to_json inside your build.yaml file (see the documentation).

What about @JsonKey annotation?

All decorators passed to a constructor parameter are "copy-pasted" to the generated property too.
As such, you can write:

@freezed
class Example with _$Example {
  factory Example(@JsonKey(name: 'my_property') String myProperty) = _Example;

  factory Example.fromJson(Map<String, dynamic> json) => _$ExampleFromJson(json);
}

What about @JsonSerializable annotation?

You can pass @JsonSerializable annotation by placing it over constructor e.g.:

@freezed
class Example with _$Example {
  @JsonSerializable(explicitToJson: true)
  factory Example(@JsonKey(name: 'my_property') SomeOtherClass myProperty) = _Example;

  factory Example.fromJson(Map<String, dynamic> json) => _$ExampleFromJson(json);
}

If you want to define some custom json_serializable flags for all the classes (e.g. explicit_to_json or any_map) you can do it via build.yaml file as described here.

See also the decorators section

Utilities

Freezed extension for VSCode

The Freezed extension might help you work faster with freezed. For example :

  • Use Ctrl+Shift+B (Cmd+Shift+B on Mac) to quickly build using build_runner.
  • Quickly generate a Freezed class by using Ctrl+Shift+P > Generate Freezed class.

Freezed extension for IntelliJ/Android Studio

You can get Live Templates for boiler plate code here.

Example:

  • type freezedClass and press Tab to generate a freezed class
    @freezed
    abstract class Demo with _$Demo {
    }
  • type freezedFromJson and press Tab to generate the fromJson method for json_serializable
    factory Demo.fromJson(Map<String, dynamic> json) => _$DemoFromJson(json);

GitHub

https://github.com/rrousselGit/freezed
Comments
  • 1. Build cannot generate files for enum and/or custom types (freezed/json_serializable)

    Describe the bug Recently, I update freezed from 1.1.1 to 2.0.2 and at generating files I'm getting the current bug:

    [SEVERE] json_serializable:json_serializable on lib/core/domain/settings/settings.entity.dart:
    
    Could not generate `toJson` code for `introductoryVideo` because of type `IntroductoryVideo`.
    package:thesis_cancer/core/domain/settings/settings.entity.freezed.dart:149:31
        ╷
    149 │   List<IntroductoryVideo> get introductoryVideo {
        │                               ^^^^^^^^^^^^^^^^^
        ╵
    package:json_serializable/src/encoder_helper.dart 136:7     EncodeHelper._serializeField
    package:json_serializable/src/encoder_helper.dart 93:26     EncodeHelper._writeToJsonWithNullChecks
    package:json_serializable/src/encoder_helper.dart 48:7      EncodeHelper.createToJson
    dart:_internal                                              WhereIterator.moveNext
    package:json_serializable/src/json_part_builder.dart 64:27  _UnifiedGenerator.generate
    package:source_gen/src/builder.dart 352:23                  _generate
    
    [FINE] json_serializable:json_serializable on lib/core/domain/settings/schedules.entity.dart:Running JsonSerializableGenerator - 1 of 2
    
    

    The problem is obviously files for IntroductoryVideo were not generated: image

    Now, the code for this entity is:

    part 'introvideo.entity.freezed.dart';
    part 'introvideo.entity.g.dart';
    
    /// [Introductory] Video Entity
    @freezed
    class IntroductoryVideo with _$IntroductoryVideo {
      /// Default builder
      const factory IntroductoryVideo({
        required UserRole role,
        required UploadFile video,
      }) = _IntroductoryVideo;
    
      /// Builds a [IntroductoryVideo] from a given json [String].
      factory IntroductoryVideo.fromJson(Map<String, Object?> json) =>
          _$IntroductoryVideoFromJson(json);
    
      /// Builds a empty(dummy) [IntroductoryVideo].
      static const IntroductoryVideo empty = IntroductoryVideo(
        role: UserRole.GUEST,
        video: UploadFile.empty,
      );
    }
    

    Where enum UserRole { ADMIN, PILOT, TEST, CONTROL, GUEST } and files for UploadFile are also generated: image

    Other classes with enum as type of one of the properties are getting the same problem:

    part 'activityfeed.entity.freezed.dart';
    part 'activityfeed.entity.g.dart';
    
    /// Activity Feed (notification) Entity
    @freezed
    class ActivityFeed with _$ActivityFeed {
      /// Default constructor
      const factory ActivityFeed({
        String? id,
        required ActivityType type,
        @Default(<String, dynamic>{}) Map<String, dynamic>? data,
        required String body,
        required String title,
        @Default(false) bool isRead,
      }) = _ActivityFeed;
    
      const ActivityFeed._();
    
      /// Builds an [ActivityFeed] from a given [String] payload.
      factory ActivityFeed.fromPayload({required String payload}) {
        final Map<String, dynamic> data =
            jsonDecode(payload) as Map<String, Object?>;
        final ActivityFeed result = ActivityFeed.fromJson(data);
        return result;
      }
    
      /// Builds an [ActivityFeed] from a given json [String].
      factory ActivityFeed.fromJson(Map<String, Object?> json) =>
          _$ActivityFeedFromJson(json);
    
      /// Builds a empty(dummy) [ActivityFeed].
      static const ActivityFeed empty = ActivityFeed(
        type: ActivityType.NEW_POST,
        body: 'New dummy feed',
        title: 'Dummy Feed',
      );
    }
    

    image

    But some others without enum variables are also getting this problem:

    part 'answer.entity.freezed.dart';
    part 'answer.entity.g.dart';
    
    ///
    @freezed
    class UserSurveyAnswer with _$UserSurveyAnswer {
      ///
      const factory UserSurveyAnswer({
        // String? id,
        required String statement,
        required String answer,
      }) = _UserSurveyAnswer;
    
      ///
      factory UserSurveyAnswer.fromJson(Map<String, Object?> json) =>
          _$UserSurveyAnswerFromJson(json);
    
      ///
      static const UserSurveyAnswer empty = UserSurveyAnswer(
        statement: '',
        answer: '',
      );
    }
    

    Hence, I deduce there is a problem with the way they are being parsed by freezed for the version 2.0.0 and on. This bug is presents from 2.0.0 version and so on, which is a big regression.

    This is my built settings:

    targets:
      $default:
        builders:
          json_serializable:
            options:
              explicit_to_json: true
              include_if_null: false
    

    To Reproduce

    import 'dart:convert';
    
    import 'package:freezed_annotation/freezed_annotation.dart';
    
    /// Notification ([ActivityFeed]) type.
    enum ActivityType {
      // NEW_COMMENT,
      // NEW_FOLLOW,
      // NEW_LIKE,
      NEW_POST,
      SCHEDULED_SURVEY_REMINDER,
      // NEW_RECOMMENDATION,
      NEW_USER_REGISTERED,
      SETTINGS_UPDATED,
      USER_CONFIRMED
    }
    
    
    
    part 'activityfeed.entity.freezed.dart';
    part 'activityfeed.entity.g.dart';
    
    /// Activity Feed (notification) Entity
    @freezed
    class ActivityFeed with _$ActivityFeed {
      /// Default constructor
      const factory ActivityFeed({
        String? id,
        required ActivityType type,
        @Default(<String, dynamic>{}) Map<String, dynamic>? data,
        required String body,
        required String title,
        @Default(false) bool isRead,
      }) = _ActivityFeed;
    
      const ActivityFeed._();
    
      /// Builds an [ActivityFeed] from a given [String] payload.
      factory ActivityFeed.fromPayload({required String payload}) {
        final Map<String, dynamic> data =
            jsonDecode(payload) as Map<String, Object?>;
        final ActivityFeed result = ActivityFeed.fromJson(data);
        return result;
      }
    
      /// Builds an [ActivityFeed] from a given json [String].
      factory ActivityFeed.fromJson(Map<String, Object?> json) =>
          _$ActivityFeedFromJson(json);
    
      /// Builds a empty(dummy) [ActivityFeed].
      static const ActivityFeed empty = ActivityFeed(
        type: ActivityType.NEW_POST,
        body: 'New dummy feed',
        title: 'Dummy Feed',
      );
    }
    

    Execute flutter pub run build_runner build --delete-conflicting-outputs --verbose.

    Expected behavior It should generate all required files.

    Setup

      freezed_annotation: ^2.0.1
      json_annotation: ^4.4.0
    dev_dependencies:
      build_runner: ^2.1.10
      flutter_test:
        sdk: flutter
      freezed: ^2.0.0
      json_serializable: ^6.1.6
      lint: ^1.8.2
    
     flutter doctor -v
    [✓] Flutter (Channel stable, 2.10.5, on Manjaro Linux 5.15.32-1-MANJARO, locale en_GB.UTF-8)
        • Flutter version 2.10.5 at /opt/flutter
        • Upstream repository https://github.com/flutter/flutter.git
        • Framework revision 5464c5bac7 (hace 4 días), 2022-04-18 09:55:37 -0700
        • Engine revision 57d3bac3dd
        • Dart version 2.16.2
        • DevTools version 2.9.2
    
    [✓] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
        • Android SDK at /home/mehmeth/Android/Sdk
        • Platform android-32, build-tools 32.1.0-rc1
        • Java binary at: /opt/android-studio/jre/bin/java
        • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)
        • All Android licenses accepted.
    
    [✓] Chrome - develop for the web
        • CHROME_EXECUTABLE = /usr/bin/chromium
    
    [✓] Android Studio (version 2021.1)
        • Android Studio at /opt/android-studio
        • Flutter plugin version 66.0.1
        • Dart plugin version 211.7817
        • Java version OpenJDK Runtime Environment (build 11.0.11+0-b60-7590822)
    
    [✓] Connected device (2 available)
        • MI 9 (mobile) • da22004 • android-arm64  • Android 10 (API 29)
        • Chrome (web)  • chrome  • web-javascript • Chromium 100.0.4896.127 Arch Linux
    
    [✓] HTTP Host Availability
        • All required HTTP hosts are available
    
    • No issues found!
    
    Reviewed by SalahAdDin at 2022-04-22 21:35
  • 2. Decorator issue with List

    Hi,

    Consider the following :

    import 'package:flutter/material.dart';
    import 'package:freezed_annotation/freezed_annotation.dart';
    import 'package:flutter/foundation.dart';
    
    import './converter/widgetList_converter.dart';
    
    part 'testFreezed.freezed.dart';
    part 'testFreezed.g.dart';
    
    @freezed
    abstract class Test2 with _$Test2 {
      const factory Test2({
        @ListWidgetModelConv() List<WidgetModel> widgets,
      }) = _Test2;
    
      factory Test2.fromJson(Map<String, dynamic> json) => _$Test2FromJson(json);
    }
    

    Generate :

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'testFreezed.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    _$_Test2 _$_$_Test2FromJson(Map<String, dynamic> json) {
      return _$_Test2(
        widgets: json['widgets'] as List,
      );
    }
    
    Map<String, dynamic> _$_$_Test2ToJson(_$_Test2 instance) {
      final val = <String, dynamic>{};
    
      void writeNotNull(String key, dynamic value) {
        if (value != null) {
          val[key] = value;
        }
      }
    
      writeNotNull('widgets', instance.widgets);
      return val;
    }
    

    Where with the corresponding Json_serialisable :

    import 'package:flutter/material.dart';
    import 'package:freezed_annotation/freezed_annotation.dart';
    import 'package:flutter/foundation.dart';
    
    import './converter/widgetList_converter.dart';
    
    part 'test.g.dart';
    
    @JsonSerializable(nullable: false)
    class Test {
      Test({
        this.widgets,
      });
    
      factory Test.fromJson(Map<String, dynamic> json) => _$TestFromJson(json);
      Map<String, dynamic> toJson() => _$TestToJson(this);
    
      @ListWidgetModelConv()
      final List<WidgetModel> widgets;
    }
    

    Generate :

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'test.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    Test _$TestFromJson(Map<String, dynamic> json) {
      return Test(
        widgets: const ListWidgetModelConv()
            .fromJson(json['widgets'] as Map<String, dynamic>),
      );
    }
    
    Map<String, dynamic> _$TestToJson(Test instance) {
      final val = <String, dynamic>{};
    
      void writeNotNull(String key, dynamic value) {
        if (value != null) {
          val[key] = value;
        }
      }
    
      writeNotNull('widgets', const ListWidgetModelConv().toJson(instance.widgets));
      return val;
    }
    

    Could you have a look ?

    Reviewed by bounty1342 at 2020-04-21 08:23
  • 3. Is it possible to integrate freezed with equatable

    I use freezed to generate state classes for bloc and would like to have equality operator overwritten (most conveniently with equatable). Sometimes I copy state with .copyWith() and it seems that implemented equality operator doesn't work in such case:

      @override
      bool operator ==(dynamic other) {
        return identical(this, other) || (other is AcceptedTerms);
      }
    

    where class is:

    part 'terms_state.freezed.dart';
    
    @freezed
    abstract class TermsState with _$TermsState {
      factory TermsState.loading() = LoadingTerms;
      factory TermsState.termsToAccept(
        TermsModel terms, {
        @Default(false) bool loading,
      }) = TermsToAccept;
      factory TermsState.accepted() = AcceptedTerms;
      factory TermsState.error() = ErrorTerms;
    }
    
    Reviewed by orestesgaolin at 2020-03-06 12:36
  • 4. Support getters

    This will not compile, or at least, no _$Person will be created. Is this something you don't want/or is impossible to support?

    @immutable
    abstract class Person with _$Person {
      const factory Person(String firstName, String lastName) = _Person;
    
      String get fullName => '$firstName $lastName';
    }
    
    Reviewed by smiLLe at 2020-02-10 16:42
  • 5. Support for json_serializable 5.0.0

    With the publication of json_serializable 5.0.0 yesterday, is it planned to update freezed to use this release?

    json_serializable >=5.0.0 depends on analyzer ^2.0.0 and freezed 0.14.2 depends on analyzer ^1.5.0, json_serializable >=5.0.0 is incompatible with freezed 0.14.2

    Reviewed by abibiano at 2021-07-14 06:21
  • 6. Nested Freezed class not converted TO JSON

    👋 Given two freezed classes where one is "nested" in the other.

    import 'package:freezed_annotation/freezed_annotation.dart';
    
    part 'contrived_example.g.dart';
    part 'contrived_example.freezed.dart';
    
    @freezed
    abstract class TopLevel with _$TopLevel {
      const factory TopLevel(
        String niceString,
        Nested doesNotSerializeButDoesDeserialize,
      ) = _TopLevel;
      factory TopLevel.fromJson(Map<String, dynamic> json) =>
          _$TopLevelFromJson(json);
    }
    
    @freezed
    abstract class Nested with _$Nested {
      const factory Nested(int niceInteger) = _Nested;
      factory Nested.fromJson(Map<String, dynamic> json) => _$NestedFromJson(json);
    }
    

    The generated code for json_serializable doesn't serialize the nested object. DEserialization works as expected.

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    part of 'contrived_example.dart';
    
    // **************************************************************************
    // JsonSerializableGenerator
    // **************************************************************************
    
    _$_TopLevel _$_$_TopLevelFromJson(Map<String, dynamic> json) {
      return _$_TopLevel(
        json['niceString'] as String,
        json['doesNotSerializeButDoesDeserialize'] == null
            ? null
            : Nested.fromJson(
                json['doesNotSerializeButDoesDeserialize'] as Map<String, dynamic>),
      );
    }
    
    Map<String, dynamic> _$_$_TopLevelToJson(_$_TopLevel instance) =>
        <String, dynamic>{
          'niceString': instance.niceString,
          // 👇 should have toJson() or map((element) => element.toJson()) for Lists
          'doesNotSerializeButDoesDeserialize':
              instance.doesNotSerializeButDoesDeserialize,
        };
    
    _$_Nested _$_$_NestedFromJson(Map<String, dynamic> json) {
      return _$_Nested(
        json['niceInteger'] as int,
      );
    }
    
    Map<String, dynamic> _$_$_NestedToJson(_$_Nested instance) => <String, dynamic>{
          'niceInteger': instance.niceInteger,
        };
    

    At first, I thought that it's an issue with json_serializable but if that library is used by itself, it serializes nested objects marked with @JsonSerializable just fine.

    Reviewed by ResoDev at 2020-03-03 11:59
  • 7. Error casting a class that has @Implements

    Hi. I have a class that has @Implements<Codable> and that generate code correctly but I can't pass the instance to a class that accept the Codable interface.

    example

    abstract class Codable {
      Map<String, dynamic> toJson();
    }
    
    @freezed
    class Example with _$Example {
      @Implements<Codable>()
      const factory Example({
        required String name,
      }) = _Example;
    
      factory Example.fromJson(Map<String, dynamic> json) => _$ExampleFromJson(json);
    }
    

    Even if we check the type using is works but that require to pass the value as an Object.

    I can't implicitly cast to Codable

    final Codable ex = Example(name: ''); // error can't be assigned
    

    or passing to a function

    void send(Codable codable) {
      print(codable.toJson());
    }
    
    void test() {
      send(Example(name: '')); // error can't be assigned
    }
    

    does I'm missing something or could there is a better way to do that? Thanks

    Reviewed by rebaz94 at 2022-06-27 14:12
  • 8. Support "non-nullable" experiment for NNBD technical preview

    I successfully migrated my early stage project to NNBD tech preview and now trying to use freezed. When I start latest build_runner with flutter pub run build_runner build --delete-conflicting-outputs --enable-experiment=non-nullable I see errors like: image

    As I suppose, the minimal change required to support NNBD is to use a new experiments library in build package somehow.

    Can NNBD be supported in freezed in some near future?..

    Reviewed by roman-petrov at 2020-06-23 02:29
  • 9. Generation issue on newer versions > 0.14.2

    freezed not generated correctly after version 0.14.2 for the following example:

    @freezed
    class GameBoardViewModel with _$GameBoardViewModel {
      const factory GameBoardViewModel({
        required final Size2D boardSize,
        required final GameStatus gameStatus,
        required final ValueSetter<Direction> onDirectionChanged,
        required final VoidCallback onSpacePressed,
      }) = _GameBoardViewModel;
    }
    

    using 0.14.2 everything is generated as expected. on newer versions the following error is thrown:

    [FINE] freezed:freezed on lib/ui/main/game_board.dart:Running FreezedGenerator
    [SEVERE] freezed:freezed on lib/ui/main/game_board.dart:
    
    Null check operator used on a null value
    package:freezed/src/tools/type.dart 15:23                    resolveFullTypeStringFrom.<fn>
    package:collection/src/iterable_extensions.dart 246:15       IterableExtension.firstWhereOrNull
    package:freezed/src/tools/type.dart 13:40                    resolveFullTypeStringFrom
    package:freezed/src/templates/concrete_template.dart 407:10  parseTypeSource
    package:freezed/src/templates/properties.dart 44:13          Property.fromParameter
    package:freezed/src/freezed_generator.dart 250:15            FreezedGenerator._parseConstructorsNeedsGeneration
    package:freezed/src/freezed_generator.dart 55:41             FreezedGenerator.parseElement
    package:freezed/src/parse_generator.dart 34:20               ParserGenerator.generate
    package:source_gen/src/builder.dart 328:23                   _generate
    
    
    Reviewed by atoka93 at 2021-09-09 13:54
  • 10. Generate "copyAs" methods

    Sometimes we have a union with common properties between the different possibilities:

    @immutable
    abstract class TodoList with _$TodoList {
      factory TodoList.data(List<Todo> todos) = TodoListData;
      factory TodoList.loading(List<Todo> todos) = TodoListLoading;
      factory TodoList.error(List<Todo> todos, [String message]) = TodoListError;
    }
    

    In such a situation, it is common to want to convert from one state to another, while preserving the common properties.

    Currently, we have to use do it ourselves:

    var todo = TodoList.data([]);
    todo = TodoList.loading(todo.todos);
    todo = TodoList.error(toto.todos, 'Error');
    

    But we could simplify that by having a copyWith that converts to a new type:

    var todo = TodoList.data([]);
    
    todo = todo.copyAsLoading();
    todo = todo.copyAsError(message: 'Error');
    
    Reviewed by rrousselGit at 2020-02-10 17:01
  • 11. Nullable field is incorrectly recognized as non-nullable

    Describe the bug Code generation fails to generate constructor that contains parameter that is at the same time:

    • derived type of another freezed class
    • nullable
    • has no default value
    • is not required

    build_runner output error:

    [SEVERE] freezed:freezed on lib/a.dart:
    
    The parameter `b` of `A` is non-nullable but is neither required nor marked with @Default
    package:fix_freezed/a.dart:9:12
      ╷
    9 │     BImpl? b,
      │            ^
      ╵
    

    If b is declared in any of the following ways, error disappears and classes are successfully generated:

    B? b
    required BImpl? b
    @Default(null) BImpl? b
    

    To Reproduce

    b.dart

    import 'package:freezed_annotation/freezed_annotation.dart';
    
    part 'b.freezed.dart';
    
    @freezed
    class B with _$B {
      factory B() = BImpl;
    }
    

    a.dart

    import 'package:freezed_annotation/freezed_annotation.dart';
    
    import 'b.dart';
    
    part 'a.freezed.dart';
    
    @freezed
    class A with _$A {
      factory A({
        BImpl? b,
      }) = _A;
    }
    

    Expected behavior Code generation creates class A that contains BImpl? type field and makes it optional in A constructor.

    Reviewed by tomwyr at 2021-03-24 12:55
  • 12. fix deprecations from analyzer: 4.4.0

    analyzer: 4.4.0 changelog

    • Deprecated DartType.element, check for InterfaceType, TypeParameterType, and then ask the element.

    No breaking changes in analyzer: 4.5.0 that effect freezed.

    Reviewed by SunlightBro at 2022-08-10 07:39
  • 13. Fail to generate class named Forecast

    Describe the bug Fail to generate class named Forecast.

    To Reproduce

    import 'package:freezed_annotation/freezed_annotation.dart';
    
    part 'forecast.freezed.dart';
    part 'forecast.g.dart';
    
    @freezed
    class Forecast with _$Forecast {
      const factory Forecast({
        @Default(0) int type,
      }) = _Forecast;
    
      factory Forecast.fromJson(Map<String, dynamic> json) =>
          _$ForecastFromJson(json);
    }
    

    Expected behavior Generate whiteout issue.

    Reviewed by bounty1342 at 2022-08-02 16:10
  • 14. Use of custom converter in freezed class

    Describe the bug I have json responses like these and these need to be serialized to BlockId Class.

    {"block_hash": "0x3871c8a0c3555687515a07f365f6f5b1d8c2ae953f7844575b8bde2b2efed27"}
    
    {"block_number": 1}
    

    and

    "block_tag"
    

    These are the 3 types of responses that I want to deserialize. I don't have a problem with the first two. It's the 3rd one that is causing an issue. The BlockId for the 1st two will have respective attributes, but for the 3rd one, itself should be a String value.

    This is my current code, but it's giving me wrong output. toJson for the 3rd type should yield a String and not a JSON.

    @freezed
    class BlockId with _$BlockId {
      const factory BlockId.blockHash({
        required StarknetFieldElement blockHash,
      }) = BlockIdHash;
      const factory BlockId.blockNumber({
        required int blockNumber,
      }) = BlockIdNumber;
      const factory BlockId.blockTag({
        required String blockTag,
      }) = BlockIdTag;
    
      factory BlockId.fromJson(Map<String, dynamic> json) =>
           _$BlockIdFromJson(json);
    
    }
    

    I came across documentation for using Converter and I tried this

    class BlockIdConverter implements JsonConverter<BlockId, dynamic> {
      const BlockIdConverter();
    
      // BlockId can be constructed from a Map as well as a String.
      @override
      BlockId fromJson(dynamic value) {
        if (value is Map) {
          Map<String, dynamic> json = value as Map<String, dynamic>;
    
          // you need to find some condition to know which type it is. e.g. check the presence of some field in the json
          if (json.containsKey('block_hash')) {
            return BlockId.blockHash(blockHash: json['block_hash']);
          } else if (json.containsKey('block_number')) {
            return BlockId.blockNumber(blockNumber: json['block_number']);
          }
        } else if (value is String) {
          return BlockId.blockTag(blockTag: value);
        }
    
        throw Exception('Could not determine the BlockId from given value: $json');
      }
    
      @override
      dynamic toJson(BlockId data) {
        return data.when<dynamic>(blockHash: (StarknetFieldElement blockHash) {
          return <String, dynamic>{'block_hash': blockHash};
        }, blockNumber: (int blockNumber) {
          return <String, dynamic>{'block_number': blockNumber};
        }, blockTag: (String blockTag) {
          return blockTag;
        });
      }
    }
    

    It's still giving me error, when I try to perform this

    BlockId blockId = valid_object;
    json.encode(blockId)
    

    It says that the toJson method is missing from the object.

    Expected behavior I would expect the 3 different types of deserialized and serialized the same via the BlockId class.

    Reviewed by prajwal27 at 2022-08-01 13:19
  • 15. feat: generate proxies for shared methods implementation

    Currently, this implementation is valid.

    @freezed
    class Shape with _$Shape {
      const Shape._();
    
      const factory Shape.square({
        required double side,
      }) = Square;
    
      const factory Shape.circle({
        required double radius,
      }) = Circle;
    
      double get area => when(
            square: (side) => pow(side, 2).toDouble(),
            circle: (radius) => pi * pow(radius, 2),
          );
    }
    
    extension ExtendedCircle on Circle {
      double get diameter => 2 * radius;
    }
    
    void main() {
      const square = Shape.square(side: 2);
      final squareArea = square.area;
    
      const circle = Shape.circle(radius: 5);
      final circleArea = circle.area;
    
      const shape = Shape._();
      final area = shape.area;
      final maybeDiameter = shape.whenOrNull(circle: (radius) => 2 * radius);
      if (circle is Circle) {
        final diameter = circle.diameter;
      }
    }
    

    However, if the implementation of the area getter were too complex or long, it would be handy to isolate it.

    One alternative to accomplish this is by using top-level functions. However, a more straightforward option would be the use of mixins that implement this shared/common behaviour, that might be identified by freezed and exposed by the base class.

    @freezed
    class Shape with _$Shape {
      const Shape._();
    
      @With<SquareMixin>()
      const factory Shape.square({
        required double side,
      }) = Square;
    
      @With<CircleMixin>()
      const factory Shape.circle({
        required double radius,
      }) = Circle;
    
      double get area => $area;
      Shape scale(double scale) => $scale(scale);
    }
    
    mixin SquareMixin {
      double get side;
    
      double get area => pow(side, 2).toDouble();
      Square scale(double scale) => Square(side: scale * side);
    }
    
    mixin CircleMixin {
      double get radius;
    
      double get area => pi * pow(radius, 2);
      Circle scale(double scale) => Circle(radius: scale * radius);
    
      double get diameter => 2 * radius;
    }
    
    // GENERATED BY FREEZED vvvvvvvvvvvvvvvvvvvv
    
    extension __$Shape on _$Shape {
      double get $area => map(
            square: (value) => value.area,
            circle: (value) => value.area,
          );
    
      Shape $scale(double scale) => map(
            square: (value) => value.scale,
            circle: (value) => value.scale,
          ).call(scale);
    }
    
    // GENERATED BY FREEZED ^^^^^^^^^^^^^^^^^^^^
    
    void main() {
      const square = Shape.square(side: 2);
      final squareArea = square.area;
    
      const circle = Shape.circle(radius: 5);
      final circleArea = circle.area;
    
      const shape = Shape._();
      final area = shape.area;
      final maybeDiameter = shape.whenOrNull(circle: (radius) => 2 * radius);
      if (circle is Circle) {
        final diameter = circle.diameter;
      }
    }
    
    Reviewed by mrverdant13 at 2022-07-26 03:42
  • 16. Allow reading common properties that share a parent class/ implementation

    The problem: We can currently read properties that are defined on all constructors as documented here. However, when a property shares a name but not the type we lose the ability to read those properties. This is true even when the property shares a parent class. Pattern matching is required to read the property when the user may have only wanted the members of its parent class.

    Consider:

    abstract class SomeInterface{}
    
    class A implements SomeInterface{}
    class B implements SomeInterface{}
    
    class Example with _$Example {
      const factory Example.someCase(A commonProperty) = SomeCase;
      const factory Example.anotherCase(B commonProperty) = AnotherCase;
      const factory Example.aThirdCase(SomeInterface commonProperty) = ThirdCase;
    }
    
    final Example example = ...
    final SomeInterface commonProperty = example.commonProperty; //does not compile
    

    The above is not possible despite each case containining a property that share a name ("commonProperty") and implementation (abstract class SomeInterface):

    Instead, pattern matching is required to read commonProperty. There may be contexts where we don't care about the union case and merely want to read the shared property as SomeInterface.

    An example API suggestion

    class Example with _$Example {
      @CommonClass<SomeInterface>("commonProperty")  
      const factory Example.someCase(A commonProperty) = SomeCase;
      const factory Example.anotherCase(B commonProperty) = AnotherCase;
      const factory Example.aThirdCase(SomeInterface commonProperty) = ThirdCase;
    }
    

    Which would then allow

    final Example example = ...
    final SomeInterface commonProperty = example.commonProperty;
    

    Would something like this be possible?

    Reviewed by LewisHolliday at 2022-07-23 21:53
  • 17. Allow $ in class name

    Is your feature request related to a problem? Please describe. I'm looking for a way to allow $ in class when freeze generate class. Let me explain. I use Mutation/Query from https://pub.dev/packages/graphql_codegen. So I got class model like this Mutation$GetUserToken with a $. But when I try to use freezed like this:

    @Freezed(makeCollectionsUnmodifiable: false)
    class Success with _$Success {
      const factory Success.refreshToken(
          Mutation$GetUserToken token) = RefreshTokenSuccess;
    }
    

    Freeze generate this:

    required TResult Function(GetUserToken token) refreshSendBirdToken,
    

    Without the $. It should be:

    required TResult Function(Mutation$GetUserSendBirdToken token) refreshSendBirdToken,
    

    Describe the solution you'd like Could be good to allow $ for name separating, a solution can be found for the moment here , it allow to change the naming separator but by default is $.

    Reviewed by Kiruel at 2022-07-22 07:38
  • Related

    Lovely Lpu is an app that has dating and chat features altered for university campuses
    Lovely Lpu is an app that has dating and chat features altered for university campuses

    Lovely is an app that has dating and chat features altered for university campuses . The app only allows users who have a registered user id with the university’s user management system also known as LPU - UMS.

    Jan 16, 2022
    Allows Dart reflection using code generation/builder.

    reflection_factory reflection_factory allows Dart reflection with an easy approach, even for third-party classes, using code generation portable for a

    Aug 3, 2022
    Naj - An open-source code generation and file management system written in Dart

    Naj An open-source code generation and file management system written in Dart Ov

    Feb 14, 2022
    The next-generation cross-platform Minecraft Launcher.

    MultiFold MultiFold is the next-generation cross-platform Minecraft launcher. This project is currently work-in-progress. Contributing You are welcome

    Jul 31, 2022
    Item selling mobile app with secure payments with Payhere payment gateway. Auto APK generation with github actions CI/CD.

    payhere_demo A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you started if

    Jan 20, 2022
    Flutter Android application for tracking Osu! user, beatmaps statistic and other features provided by Osu! API

    TMP-team-2-Osu-track Целью проекта является написание приложения на платформе Android и IOS с помощью Dart+Flutter с интуитивно понятным интерфейсом,

    Jul 7, 2022
    Utility classes/functions to help with UI development using the Flutter framework.

    Aqua Utility classes/functions to help with UI development using the Flutter framework. It is recommended to use the as keyword with the import statem

    Jul 17, 2022
    🎵 Elegant music app to play local music & YouTube music. Distributes music into albums & artists. Has playlists & lyrics.
    🎵 Elegant music app to play local music & YouTube music. Distributes music into albums & artists. Has playlists & lyrics.

    Harmonoid Elegant music app to play local music & YouTube music. Download Now ?? Feel free to report bugs & issues. We'll be there to fix. Loving the

    Aug 13, 2022
    This is a smart farming app which helps farmers to remotely monitor their crop and take necessary actions. It also has a feature called disease detection.

    Smart-Farming-App This is a smart farming app which helps farmers to remotely monitor their crop and take necessary actions. It has features called di

    Jul 9, 2022
    A modern voice chat application. The project has been written solely in Dart Language.
    A modern voice chat application. The project has been written solely in Dart Language.

    VChat A modern voice chat application. The application welcomes the user with the login screen. After a simple registration process, an empty "Home" s

    Jun 13, 2022
    The application helps the patient to follow up on medication schedules, and each patient has his own profile. The application is connected to Bluetooth to help the patient's dependents follow up on the patient.

    spoon_medicines A new Flutter application. Getting Started This project is a starting point for a Flutter application. A few resources to get you star

    Nov 27, 2021
    Just another tape player has been written in Flutter for iOS and Android
    Just another tape player has been written in Flutter for iOS and Android

    Just another tape player has been written in Flutter for iOS and Android. The application is able to find tapes and theirs images using https://zxInfo.dk public API and upload them to ZX-Spectrum compatible computers by the audio output of the smartphone. Now it supports TAP and TZX tape images only.

    Jul 16, 2022
    🎵 Elegant music app to play local music & YouTube music. Distributes music into albums & artists. Has playlists & lyrics. Windows + Linux + Android.
    🎵 Elegant music app to play local music & YouTube music. Distributes music into albums & artists. Has playlists & lyrics. Windows + Linux + Android.

    Harmonoid Elegant music app to play local music & YouTube music. Download Now ?? Windows, Linux & Android. Feel free to report bugs & issues. Loving t

    Aug 10, 2022
    I did a task manager which has abilities like (priority,sort,daily,weekly,monthly,profile screen,user auth)

    task_manager A task manager app by Flutter. Getting Started This is a task manager app which you can manage your daily/weekly/monthly tasks. Users can

    Jan 12, 2022
    The Drawer Manager class has the ability to swap Scaffold body contents, using a custom provider
    The Drawer Manager class has the ability to swap Scaffold body contents, using a custom provider

    The Drawer Manager class has the ability to swap Scaffold body contents, using a custom provider. Open Drawer Hello, Flutter! Counter The MAC All Page

    Mar 18, 2022
    Weather-App-Api- - Simple Realtime Weather App With Api
    Weather-App-Api- - Simple Realtime Weather App With Api

    music_app A new Flutter Weather App project. Getting Started // اول حاجه تعمل en

    Aug 4, 2022
    Platform to post/say something without sharing personal information.
    Platform to post/say something without sharing personal information.

    Anon is an Open Source Application where it's users will be able to share their thoughts without their identity being revealed i.e Anonymous. When the

    May 10, 2022
    An architecture for dynamic UI without client deployment

    Server Driven UI Demo Server Driven UI(SDUI)는 서버에서 클라이언트의 UI 컴포넌트를 관리하는 방식. 클라이언트 배포없이 API 응답을 변경하는 것만으로 UI 변경이 가능한 동시에 하위 호환성을 확보할 수 있다. Rust, GraphQ

    Jun 20, 2022
    A Dart/Flutter package to register/query/remove URI Schemes without hassle.

    protocol_registry Register/query/remove URI Schemes without hassle. Available for Windows and Linux. Installation flutter pub add protocol_registry Us

    Jul 25, 2022