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
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.