18

I am using the following plugin: https://pub.dev/packages/freezed

I want to subclass a freezed data class to provide additional functionality in my data layer. So I have my data class which looks like:

import 'dart:ui';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'card.freezed.dart';

@freezed
abstract class Card with _$Card {
  factory Card({String text, Color color, List<String> categories}) = _Card;
}

Now I want to have this Card class as a super class to my CardModel so that the CardModel has access to the same fields, the copyWith method, value equality, ... But I have no Idea how to go about this. I am trying something like this:

import 'package:flutter/widgets.dart';
import 'package:growthdeck/features/card_deck/domain/entities/card.dart';

import '../../domain/entities/card.dart';

abstract class CardModel extends Card {
  factory CardModel.fromMap(Map<String, dynamic> card) => Card(
        text: card["text"],
        color: Color(int.parse(card['color'])),
        categories: card['categories'] as List<String>,
      );
}

Which throws the following error:

package:growthdeck/features/card_deck/data/models/card_model.dart 11:9  new CardModel.fromMap
test/features/card_deck/data/models/card_model_test.dart 13:23          main.<fn>

type '_$_Card' is not a subtype of type 'CardModel' in type cast

Is there any way to do this properly? My workaround would be to simply "wrap" the Card class inside the CardModel and provide a toCard() method which is not very elegant :S

Marco Papula
  • 741
  • 2
  • 8
  • 18
  • 8
    Freezed classes are not made to be subclassed – Rémi Rousselet Aug 06 '20 at 14:17
  • @RémiRousselet Is there a way to work around this issue? :S Or is the whole idea of what I am trying to do bad? – Marco Papula Aug 06 '20 at 15:30
  • and also is there a specific reason they are not made to be subclassed or simply because there was/is no need for them to be? – Marco Papula Aug 06 '20 at 15:42
  • 6
    No, there is no way to work around this issue. This is a requirement for copyWith to work properly. Use Object Composition instead of Inheritance – Rémi Rousselet Aug 06 '20 at 16:32
  • 1
    @RémiRousselet alright thank you :) If you post this as an answer I can accept it :) – Marco Papula Aug 07 '20 at 13:17
  • @MarcoPapula why would you want to put `fromMap` into a subclass, and not into the freezed data class itself? And why don't you use json_serialize to implement a `fromJson` automatically, which basically does exactly the samething.. (minus the Color conversion thing, where you would have to write a deserializer, but it's trivial and less repetitive) – Herbert Poul Jul 22 '21 at 18:24
  • @HerbertPoul I don't want the fromMap function in my freezed data class because it does not belong there. It's data layer code. The model belongs to the domain layer and does not need to know how it was parsed. I admit it's a small thing but still. Using extensions I can easily do exactly what I need in case anyone has the same issue :). As for the json_serializable package, it was easier to convey my issue with freezed without including code from other packages ;D – Marco Papula Jul 24 '21 at 10:26
  • @MarcoPapula it sounds like you are segregating classes appropriately. i've run into something similar. my case is that i am doing more type driven development and trying to refactor. The only difference between these classes is a "type" indicator. I want to be sure that my methods are getting the type they expect and the caller must send said type. It is safer. Did you do as Remi suggested, then? Seems a bit ugly, but... Can you post your final solution? – Bill Turner Mar 07 '22 at 19:48

2 Answers2

10

Freezed doesn’t support inheritance at the moment so it’s recommended to use composition instead of inheritance as mentioned by the creator here:

https://github.com/rrousselGit/freezed/issues/464

And in the comments of the post.

Abdelghani Bekka
  • 576
  • 9
  • 18
0

Freezed class subclass itself. You dont need to abstract it.

import 'dart:ui';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'card.freezed.dart';

@freezed
class Card with _$Card {
 const factory Card.cardModel({String text, Color color, List<String> categories}) = _$CardModel;
}

Run build runner for above freeze will create

abstract class _$CardModel implements Card{}

which you can access by Card factory.