Search code examples
flutterdartfreezedflutter-freezed

Filter by Freezed Generic Field


I have a Freezed generated class with two factory constructors, both containing the same field that is a generic. Given a list of this class I would like to be able to filter based on the type that the field is.

Here is my class:

@freezed
sealed class Artifact<T extends Location> with _$Artifact<T> {
  const Artifact._();

  const factory Artifact.FromServer(
      {required String id,
      @_LocationConverter() required T location
}) = ServerArtifact<T>;

  const factory Artifact.NewArtifact({
    @_LocationConverter() required T location,
  }) = NewArtifact<T>;

  factory Artifact.fromJson(Map<String, Object?> json) =>
      ServerArtifact.fromJson(json);
}

My generic type Location is a Freezed union that can either be a point or a polygon.

With this class I can create new Artifacts like:

final newArtifact = Artifact.NewArtifact(
    location: Location.FromPoint(
      latitude: curLocation.latitude,
      longitude: curLocation.longitude,
    ),
  );

The problem with creating artifacts like this, is when I debugged my application it looks like Dart is storing the type of newArtifact as _$NewArtifactImpl<Location> -- even if I'm passing in a Location.fromPoint() (which returns as PointLocation class that extends Location). So if I add newArtifact to a list I am unable to filter using the whereType<Artifact<PointLocation>>(). To get around this I made my own custom filter as shown below:

List<Artifact<PointLocation>> get pointArtifacts => artifacts
    .where((a) => a.location is PointLocation)
    .map<Artifact<PointLocation>>((a) => a as Artifact<PointLocation>)
    .toList();

However, when this runs I get the error:

type '_$NewArtifactImpl' is not a subtype of type 'Artifact' in type cast

I would not only like to filter to get artifacts with a PointLocation, but also be able to be able to narrow the type of Artifact to Artifact


Solution

  • Instead of creating an Artifact by using the typical Freezed factory constructor without explicitly setting generics I was able to create my artifact as follows:

    final newArtifact = Artifact<PointLocation>.NewArtifact(
      title: title,
      description: description,
      location: PointLocation(
        latitude: curLocation.latitude,
        longitude: curLocation.longitude,
      ),
    );
    

    Which then allowed me to use the whereType array filtering.