Welcome to the Macro version of Freezed!
It has been renamed to dataclass
, for the sake of enabling users to
temporarily use both build_runner
and macros.
This is a tool that generates toString
, copyWith
(including copyWith(field: null)
), hashCode
, ==
and more.
This is a very early proof of concept about what Freezed would look like when macros land in Dart. Beware: Due to many missing Macro features, lots of Freezed features are missing or broken. Use at your own risk :)
Installation
To get started with the macro version of Freezed:
-
Make sure that you use a Dart version >= 3.5.0-dev
-
Enable
macros
in youranalysis_options.yaml
as followed:# analysis_options.yaml analyzer: enable-experiment: - macros
-
Install Freezed >= 3.0.0:
name: your_app environment: sdk: ">=3.5.0-0.0-dev <4.0.0" dependencies: # Freezed is now a "dependencies". # freezed_annotation is no-longer needed dataclass: ^3.0.0-0.0.dev
Usage
Two possible syntaxes are supported:
-
Constructor-first. You define a class with a constructor, and the macro will generate fields for you. This gives fine-grained control over positional vs named parameters. It offers the ability to use asserts,
super
, ... Although macros have still lots of things related to this that don't work. So although the syntax is very flexible, lots of things are not supported yet. -
Field-first. You define a class with fields, and the macro will generate a constructor for you. This is the most stable syntax. But it is less flexible, and not very dart-like. If you want full control over constructors, you'll have to use the constructor-first syntax.
Constructor-first usage
To use the constructor-first syntax, define a class with a constructor, but no fields:
@Data()
class Example {
Example({required int foo, required String bar});
}
The macro will generate the fields for you, along with the various methods.
void main() {
final example = Example(foo: 42, bar: '42');
print(example.foo); // 42
}
Using named constructors.
Naturally, the macro expects that you use the default constructor.
If you wish to generate fields based on a named constructor instead,
specify @Data(constructor: '<constructor name>')
.
@Data(constructor: 'custom')
class Example {
Example.custom({required int foo, required String bar});
}
Field-first usage
To use the field-first syntax, define a class with fields but default constructor. The macro will then generate a constructor for you, along with the various methods.
@Data()
class Example {
final int foo;
final String bar;
}
Currently, all fields are "named" parameters, and they are optional if they are nullable.
void main() {
final example = Example(foo: 42, bar: '42');
print(example.foo); // 42
}
Specifying the constructor name
If you wish to generate a non-default constructor,
you can specify @Data(constructor: '<constructor name>')
.
@Data(constructor: 'custom')
class Example {
final int foo;
}
void main() {
final example = Example.custom(foo: 42);
}
Features
features | status | comment |
---|---|---|
copyWith | ✅ | |
toString | ✅ | |
==/hashCode | ✅ | |
unions | 🚧 | Supported, but macros are a bit bugged with regards to class inheritance. |
json support | 🚧 | |
default values | ❌ | Requires macros to be more developed |
deep copy | ❌ | Requires macros to be more developed |
generic classes | ❌ | Requires macros to be more developed |