Freezed: Error when I use Nested generic freezed type

Created on 29 Mar 2020  路  7Comments  路  Source: rrousselGit/freezed

When I write nested generic freezed type, compiler puts errors.

My code is below.

  • Inner is a freezed class which has a generic type I.
  • Outer is also a freezed class which contains a Inner<int>.

inner.dart

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

part 'inner.freezed.dart';

@freezed
abstract class Inner<I> with _$Inner<I> {
  const factory Inner({
    I data,
  }) = _Inner<I>;
}

and outer.dart

import 'package:flutter/foundation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:freezed_generics/inner.dart';

part 'outer.freezed.dart';

@freezed
abstract class Outer with _$Outer {
  const factory Outer({
    Inner<int> innerData,
  }) = _Outer;
}

The code generation is succeeded. But generated code causes (four) errors.

error: The name 'I' isn't a type so it can't be used as a type argument. (non_type_as_type_argument at [freezed_generics] lib/outer.freezed.dart:36)
error: The name 'I' isn't a type so it can't be used as a type argument. (non_type_as_type_argument at [freezed_generics] lib/outer.freezed.dart:57)
error: The name 'I' isn't a type so it can't be used as a type argument. (non_type_as_type_argument at [freezed_generics] lib/outer.freezed.dart:61)
error: The name 'I' isn't a type so it can't be used as a type argument. (non_type_as_type_argument at [freezed_generics] lib/outer.freezed.dart:74)

When I replace above I to int in generated outer.freezed.dart manually, the code seems to work fine. Is this expected behavior? Do I missed some usages? (I'm new to Dart and Flutter :pray: )

I attached a reproduction project (as zip file).

freezed_generics.zip

Thanks for great package! :heart: :heart:

bug

Most helpful comment

Thanks for the report!

It looks like a bug. I'll investigate

All 7 comments

Thanks for the report!

It looks like a bug. I'll investigate

I've pin-pointed the problem and know the fix.
But to make the fix, I need an extra information: the generic parameters passed to the object (int for List<int>)

Sadly, I don't see any way to obtain this information.

Actually I found the solution through luck

Hi @rrousselGit

I also have the issue.

Could not generate `fromJson` code for `data` because of type `T` (type parameter).
None of the provided `TypeHelper` instances support the defined type.
To support type paramaters (generic types) you can:
1) Use `JsonConverter`
  https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonConverter-class.html
2) Use `JsonKey` fields `fromJson` and `toJson`
  https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/fromJson.html
  https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonKey/toJson.html
3) Set `JsonSerializable.genericArgumentFactories` to `true`
  https://pub.dev/documentation/json_annotation/latest/json_annotation/JsonSerializable/genericArgumentFactories.html
package:melodyo/domain/core/response.freezed.dart:152:11

and my freezed class is:

import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:json_annotation/json_annotation.dart';

part 'response.freezed.dart';
part 'response.g.dart';

@freezed
abstract class Response<T> with _$Response<T> {
  const factory Response({
    T data,
    String message,
    Map<String, dynamic> errors,
    Map<String, dynamic> links,
    Map<String, dynamic> meta,
  }) = _Response<T>;

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

There is no way to deserialize T, because that could be anything.

Either use a Converter (see https://github.com/rrousselGit/freezed#fromjson---classes-with-multiple-constructors), or change how you model your data to not rely on generics.

Maybe change your Response to:

@freezed
abstract class Response<T> with _$Response<T> {
  const factory Response({
    Map<String, Object> data,
    String message,
    Map<String, Object> errors,
    Map<String, Object> links,
    Map<String, Object> meta,
  }) = _Response<T>;

  factory Response.fromJson(Map<String, Object> json) =>
      _$ResponseFromJson(json);
}

and deserialize data separately.

Hi @rrousselGit
Ok, the data could be a Map or a List or anything else.
I will deserialize data separately but hope you find a way to deserialize generic types.
Thanks.

That's simply not feasible

Was this page helpful?
0 / 5 - 0 ratings