Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
363 views
in Technique[技术] by (71.8m points)

flutter - Dart - Problem replicating sealed classes like kotlin

I'm getting this error on a starting example that I'm writing

type 'Error<dynamic>' is not a subtype of type 'FutureOr<Success<List<TaskEntity>>>'

I've created a generic Result class like this:

enum DataStatus { local, remote, error }

enum ErrorStatus { unknown, backend_error, timeout }

@sealed
abstract class Result<T> {}

class Success<T> extends Result<T> {
  final T data;
  final DataStatus dataStatus;
  final String message;

  Success({this.data, this.dataStatus, this.message});
}

class Error extends Result {
  final Exception exception;
  final ErrorStatus errorStatus;
  final String message;

  Error({this.exception, this.errorStatus, this.message});
}

On my repository I have this method:

Future<Result<List<TaskEntity>>> getTasks() {
    return remoteDataSource
      .getTasks()
        .then((value) => Success(
            data: value.map((e) => e.toTaskEntity()).toList(),
            dataStatus: DataStatus.remote))
        .catchError((Object obj) {
      switch (obj.runtimeType) {
        case DioError:
          final dioErrorResponse = (obj as DioError).response;
          return Error(
              exception: Exception(dioErrorResponse.statusMessage),
              errorStatus: ErrorStatus.backend_error,
              message: dioErrorResponse.statusMessage);
          break;
        default:
      }
    });

My approach is to use this class to return the responses and If there's an error return the error.

Right now I'm blocked because I'm getting this error

type 'Error<dynamic>' is not a subtype of type 'FutureOr<Success<List<TaskEntity>>>'

I also tried to use the freezed library but no luck.

 part 'result.freezed.dart';

 @freezed
 abstract class Result<T> with _$Result<T> {
   const factory Result.success({T data, DataStatus dataStatus, String message}) = Success<T>;
   const factory Result.error({Exception exception, ErrorStatus errorStatus,  String message}) = Error;
 }
question from:https://stackoverflow.com/questions/65904772/dart-problem-replicating-sealed-classes-like-kotlin

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your problem is that you never specified a T for your error class, neither directly, nor implicitely. So it is an Error<dynamic>. But an Error<dynamic> does not extend Result<List<TaskEntity>>. An Error<List<TaskEntity>> would. So you need to make sure that your Error class gets a type for T too.

To be honest the whole .then .catch thing is way to complicated for me. I would have used async and await with normal try/catch blocks. But if you want to keep it as it is, at least make sure you do this:

return Error<List<TaskEntity>>(

so your Error<> class is of the right type syntactically.


Just as an example of what I mean by making it easier by using async and await:

Future<Result<List<TaskEntity>>> getTasks() async {
   try {
     final results = await remoteDataSource.getTasks();
     final tasks = results.map((e) => e.toTaskEntity()).toList()

     return Success<List<TaskEntity>>(data: tasks, dataStatus: DataStatus.remote);
   } catch (e) {
       if (e is DioError) {
           return Error<List<TaskEntity>>(
             exception: Exception(e.response.statusMessage),
             errorStatus: ErrorStatus.backend_error,
             message: e.response.statusMessage);
       } else {
         // you are missing a case here? what do you want to return here?
       }
   }
}

For me this is a lot easier to read, to the point where it's obvious you are missing a case. There needs to be a return statement there.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...