I have a Flutter class that uses Freezed to create a sealed union that represents either data or an error:
@freezed
class DataOrError<T, E> with _$DataOrError {
const factory DataOrError.loading() = Loading;
const factory DataOrError.data(T data) = DataOrE<T, E>;
const factory DataOrError.error(E error) = DOrError<T, E>;
static DataOrError<T, E> fromEither<T, E>(Either<E, T> val) {
final result = val.fold(
(l) => DataOrError<T, E>.error(l), (r) => DataOrError<T, E>.data(r));
return result;
}
}
I use riverpod so I have a riverpod StateNotifier that looks like:
class RolesNotifier
extends StateNotifier<DataOrError<List<Role>, RoleFailure>> {
final Ref _ref;
StreamSubscription? sub;
RolesNotifier(Ref ref)
: _ref = ref,
super(const DataOrError.loading());
/// Will run the fetch
void fetch() {
// fetch roles
state = const DataOrError.loading();
sub = _ref.read(firebaseRoleService).getRoles().listen((event) {
state = DataOrError.fromEither<List<Role>, RoleFailure>(event);
});
}
// ... this class has been shortened for simplicity.
}
final rolesProvider = StateNotifierProvider.autoDispose<RolesNotifier,
DataOrError<List<Role>, RoleFailure>>((ref) {
return RolesNotifier(ref);
});
When I consume this provider; however, the types for DataOrError are gone:
ref
.read(rolesProvider)
.when(loading: (){}, data: (d) {
// d is dynamic type not List<Role>
}, error: (e){});
For some reason both d
and e
are dynamic types and not List<Role>
& RoleFailure
respectively. Everything appears to be typed correctly so why is this not working? I'm not sure if the error is with Freezed or Riverpod. I would like to avoid type casting (i.e. d as List<Role>
) because that defeats the purpose of the generics.