jonataslaw / getx

Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
MIT License
10.42k stars 1.63k forks source link

Typed return values for named routes #734

Open saschaernst opened 4 years ago

saschaernst commented 4 years ago

Is your feature request related to a problem? Please describe. When typing a call like

final result = await Get.toNamed<String>('/somePage');

I get the error message

E/flutter (10554): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)] Unhandled Exception: type 'GetPageRoute<dynamic>' is not a subtype of type 'Route<String>?' in type cast

when loading that page.

Describe the solution you'd like It would be really nice to have typed return values when using named routes. Would that be possible?

Describe alternatives you've considered When I use

final result = await Get.to<String>(SomePage());

it works as expected.

eduardoflorence commented 4 years ago

1) To receive arguments from a route you must use async / await:

() async {
  final result = await Get.toNamed<String>('/somePage');
  print(result);
}

2) The error is probably caused by your Get.back (), how is your code? Here's an example:

Get.back(result: 'return value');
eduardoflorence commented 4 years ago

Instead of async/wait you can also use then():

Get.toNamed('/somePage').then((value) => print(value));
saschaernst commented 4 years ago

But it would still be dynamic, right? That also works with async/await

eduardoflorence commented 4 years ago

Sorry I didn't understand your question now, could you give more details?

saschaernst commented 4 years ago

Apologies for the confusion by forgetting the 'await'. Just to be clear, this is not a bug report but a feature request. I'd just like to be able to type the expected return value from a named route as it works with a normal one.

Works (result is String):

final result = await Get.to<String>(SomePageReturningAString());

Works (but result is unfortunately dynamic):

final result = await Get.toNamed('/somePageReturningAString');

Does not work (Unhandled Exception as mentioned before):

final result = await Get.toNamed<String>('/somePageReturningAString');
eduardoflorence commented 4 years ago

@saschaernst is really giving an error when doing navigation by named route when typing the return.

@jonataslaw can be sure that this is a mistake.

I did a study in the source code of the Get package and I could see that toNamed (Get) calls pushNamed (Flutter) and this calls the method defined in the onGenerateRoute property, which is in MaterialApp without passing the Type, so a PageRoute dynamic is always returned.

@jonataslaw, if we do this:

final result = await Get.toNamed<String>('/somePage');`

The generator method ingetx\lib\get_navigation\src\root\root_widget.dart should return:

return GetPageRoute<String>(...

but it returns:

return GetPageRoute(... // that is, GetPageRoute<dynamic>(...

Then the error mentioned in this issue occurs in the flutter code in flutter\lib\src\widgets\navigator.dart, in the method _routeNamed<T>, exactly on this line:

Route<T> route = widget.onGenerateRoute(settings) as Route<T>;

Error: 'GetPageRoute\<dynamic>' is not a subtype of type 'Route\<String>'

I wanted to help with a PR, but I can't think of a way for the generator method of named routes to receive the Type without changing the Flutter code. The only thing I thought would be to set the return type in GetPage and get it in the generator method, but it would limit us to having only one return type per page.

eduardoflorence commented 4 years ago

@saschaernst a solution if you need to type the return, would be to do so:

() async {
  final returnValue = await Get.toNamed('/somePage'); // without type
  final String result = returnValue;
}
saschaernst commented 4 years ago

@eduardoflorence Thanks for investing your time and researching the topic.

PS: you can do it in one line

final String result = await Get.toNamed('/somePage');
saschaernst commented 4 years ago

I leave this open in case someone has a solution or any final verdict for this problem

seekcx commented 3 years ago

Is there any progress on this issue?

lvyandev commented 3 years ago

I think it should not be dynamic or generic T is useless.

yanhao98 commented 3 years ago

+1

Hwan-seok commented 3 years ago

@eduardoflorence Thanks for investing your time and researching the topic.

PS: you can do it in one line

final String result = await Get.toNamed('/somePage');

Thank you for reporting and introducing alternative solutions! But it does not work now because the route result can be always nullable. so we have to do it as follows but throws the same exception.

final String? result = await Get.toNamed('/somePage'); Unhandled Exception: type 'GetPageRoute\<dynamic>' is not a subtype of type 'Route\<String>?' in type cast

We should use the solution of @eduardoflorence now

seel-channel commented 2 years ago

I uses GetPage and Navigator.of(context). It works fine

  final value = await navigator?.pushNamed(
    MultipleProductsSameBarcodeBottomSheet.route,
    arguments: values,
  );

It has error when I typed the returned value and displays this log:

  final Object? value = await navigator?.pushNamed(
    MultipleProductsSameBarcodeBottomSheet.route,
    arguments: values,
  );

E/flutter ( 5064): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'GetPageRoute<dynamic>' is not a subtype of type 'Route<Object>?' in type cast

Solution: Dont type return value, you should add a if comparation if returned value is correct.

if (value is Product) {}
jordanmaulana commented 1 year ago

I got the same issue and really want to declare the data type instead of using just final or dynamic.

What I did is:

final String? result = await Get.toNamed('/somePage') as String?;

Set as nullable to handle user clicking back button.

xErik commented 1 year ago

get: ^4.6.5

Works not:

final Budget? res = await Get.toNamed<Budget?>('DialogBudgetEdit',
        arguments: {'budget': budget});

Expected a value of type 'Route<Budget?>?', but got one of type 'GetPageRoute<dynamic>'

Works:

final Budget? res = await Get.toNamed('DialogBudgetEdit',
        arguments: {'budget': budget}) as Budget?;
AoEiuV020 commented 6 months ago

My current solution is like this,

final String? result = await Get.toNamed<dynamic>('/somePage');

it feels quite ugly to me. I also hope to avoid using dynamic if possible.