Freezed
Code generation for immutable classes that has a simple syntax/API without compromising on the features.
Install / Use
/learn @rrousselGit/FreezedREADME
English | 한국어 | 简体中文 | 日本語 | Tiếng Việt
<a href="https://discord.gg/GSt793j6eT"><img src="https://img.shields.io/discord/765557403865186374.svg?logo=discord&color=blue" alt="Discord"></a>
Welcome to [Freezed], yet another code generator for data classes, tagged unions, nested classes and cloning.
Migration to 3.0.0
To migrate from 2.0.0 to 3.0.0, see changelog and our migration guide.
Motivation
Dart is awesome, but defining a "model" can be tedious. You have to:
- Define a constructor + properties
- Override
toString,operator ==,hashCode - Implement a
copyWithmethod to clone the object - Handle (de)serialization
Implementing all of this can take hundreds of lines, which are error-prone and affect the readability of your model significantly.
Freezed tries to fix that by implementing most of this for you, allowing you to focus on the definition of your model.
| Before | After |
| ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
|
Index
- Migration to 3.0.0
- Motivation
- Index
- How to use
- Utilities
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:
For a Flutter project:
flutter pub add \
dev:build_runner \
freezed_annotation \
dev:freezed
# if using freezed to generate fromJson/toJson, also add:
flutter pub add json_annotation dev:json_serializable
For a Dart project:
dart pub add \
dev:build_runner \
freezed_annotation \
dev:freezed
# if using freezed to generate fromJson/toJson, also add:
dart pub add json_annotation dev:json_serializable
This installs three packages:
- build_runner, the tool to run code-generators
- [freezed], the code generator
- freezed_annotation, a package containing annotations for [freezed].
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.
To do that, you can add the following to the analysis_options.yaml file
at the root of your project:
analyzer:
errors:
invalid_annotation_target: ignore
Run the generator
To run the code generator, execute the following command:
dart run build_runner watch -d
Note that like most code-generators, [Freezed] will need you to both import the annotation ([freezed_annotation])
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.
Creating a Model using Freezed
Freezed offers two ways of creating data-classes:
- Primary constructors ; where you define a constructor and Freezed generates the associated fields.
This is simulating the Primary Constructor using
factory. - Classic classes, where you write a normal Dart class and Freezed only handles
toString/==/copyWith
Primary constructors
Freezed implements Primary Constructors by relying on factory constructors.
The idea is, you define a factory and Freezed generates everything else:
import 'package:freezed_annotation/freezed_annotation.dart';
// required: associates our `main.dart` with the code generated by Freezed
part 'main.freezed.dart';
// optional: Since our Person class is serializable, we must add this line.
// But if Person was not serializable, we could skip it.
part 'main.g.dart';
@freezed
abstract class Person with _$Person {
const factory Person({
required String firstName,
required String lastName,
required int age,
}) = _Person;
factory Person.fromJson(Map<String, Object?> json) => _$PersonFromJson(json);
}
The following snippet defines a model named Person:
Personhas 3 properties:firstName,lastNameandage- Because we are using
@freezed, all of this class's properties are immutable. - Since we defined a
fromJson, this class is de/serializable. Freezed will add atoJsonmethod for us. - Freezed will also automatically generate:
- a
copyWithmethod, for cloning the object with different properties - a
toStringoverride listing all the properties of the object - an
operator ==andhashCodeoverride (sincePersonis immutable)
- a
From this example, we can notice a few things:
-
It is necessary to annotate our model with
@freezed(or@Freezed/@unfreezed, more about that later).
This annotation is what tells Freezed to generate code for that class. -
We must also apply a mixin with the name of our class, prefixed by
_$. This mixin is what defines the various properties/methods of our object. -
When defining a constructor in a Freezed class, we should use the
factorykeyword as showcased (constis optional).
The parameters of this constructor will be the list of all properties that this class contains.
Parameters don't have to be named and required. Feel free to use positional optional parameters if you want!
Adding getters and methods to our models
Sometimes, you may want to manually define methods/properties in our classes.
But you will quickly notice that if you try to use primary constructors:
@freezed
abstract class Person with _$Person {
const factory Person(String name, {int? age}) = _Person;
void method() {
print('hello world');
}
}
then it will fail with
