diff --git a/packages/freezed/README.md b/packages/freezed/README.md index 7ef58773..9ecb7a96 100644 --- a/packages/freezed/README.md +++ b/packages/freezed/README.md @@ -55,6 +55,7 @@ to focus on the definition of your model. - [Mixins and Interfaces for individual classes for union types](#mixins-and-interfaces-for-individual-classes-for-union-types) - [FromJson/ToJson](#fromjsontojson) - [fromJSON - classes with multiple constructors](#fromjson---classes-with-multiple-constructors) + - [genericArgumentFactories](#generic-argument-factories---serializing-generic-types) - [Configurations](#configurations) - [Changing the behavior for a specific model](#changing-the-behavior-for-a-specific-model) - [Changing the behavior for the entire project](#changing-the-behavior-for-the-entire-project) @@ -1074,6 +1075,64 @@ In order to serialize nested lists of freezed objects, you are supposed to eithe specify a `@JsonSerializable(explicitToJson: true)` or change `explicit_to_json` inside your `build.yaml` file ([see the documentation](https://github.com/google/json_serializable.dart/tree/master/json_serializable#build-configuration)). +### Generic argument factories - serializing generic types + +In order to serialize generic typed freezed objects, you can either specify a type converter, or you can enable `genericArgumentFactories`. + +If you know how to serialize all values of that generic type (such as when you bound the generic type with a type that you control) you can use a type converter: + +```dart +@freezed +class MyModel with _$MyModel { + const factory MyModel(@MyTConverter() T myResponse) = MyModelData; + + factory MyModel.fromJson(Map json) => _$MyModelFromJson(json); +} + +class MyTConverter implements JsonConverter { + const MyTConverter(); + + @override + KnownType fromJson(dynamic json) => // TODO: Convert from json + + @override + dynamic> toJson(KnownType data) => // TODO: Convert to json +} +``` + +If you don't know all of the types that could be used and want the user of the object to be able to pass functions to handle the serialization of the generic type consider using `genericArgumentFactories`. + +All you need to do is change the signature of the `fromJson` method and add `genericArgumentFactories: true` to the freezed configuration. + +```dart +@Freezed(genericArgumentFactories: true) +class ApiResponse with _$ApiResponse { + const factory ApiResponse.data(T data) = ApiResponseData; + const factory ApiResponse.error(String message) = ApiResponseError; + + factory ApiResponse.fromJson(Map json, T Function(Object?) fromJsonT) => _$ApiResponseFromJson(json, fromJsonT); +} +``` + +Using genericArgumentFactories will also generate a `toJson` method with a slightly different signature: + +```dart +Map toJson(Object? Function(T) toJsonT); +``` + +This also works with multiple type arguments, with one parameter per argument. The convention is to name the arguments `toJson$typeArg` and `fromJson$typeArg`. + +If creating many classes with this freezed configuration consider altering the global configuration of freezed using the `build.yaml` file. + +```yaml +targets: + $default: + builders: + freezed: + options: + generic_argument_factories: true +``` + **What about `@JsonKey` annotation?** All decorators passed to a constructor parameter are "copy-pasted" to the generated