a14n / dart-google-maps

A library to use Google Maps JavaScript API v3 from Dart scripts.
Apache License 2.0
130 stars 66 forks source link

Encoding.decodePath throws when running with webdev serve #113

Closed deedub-g closed 2 years ago

deedub-g commented 2 years ago

Example error Uncaught Error: Expected a value of type 'List<google.maps.LatLng?>?', but got one of type 'List<dynamic>'

Note that the error did not occur for me when running dart 2.16.1 -- it only started after upgrading to dart 2.17.3.

Reproduction steps:

pubspec.yaml

name: quickstart
description: An absolute bare-bones web app.
version: 1.0.0

environment:
  sdk: '>=2.16.1 <3.0.0'

dependencies:
  google_maps:

dev_dependencies:
  build_runner: ^2.1.4
  build_web_compilers: ^3.2.1
  lints: ^1.0.0

web/main.dart

import 'dart:html';

import 'package:google_maps/google_maps.dart';
import 'package:google_maps/google_maps_geometry.dart';

void main() {
  try {
    var path = [LatLng(34.3664951, -89.5192484)];
    var encoded = Encoding.encodePath(path);
    print('encoded: $encoded');
    var decoded = Encoding.decodePath(encoded);
    print('decoded.first ${decoded?.first}');
    document.body!.appendText('no errors');
  } catch (e) {
    document.body!.appendText('ERRORS');
    rethrow;
  }
}

Then run webdev serve and access the web-app. I imagine you could reproduce as well from the examples in this repo, but it wasn't obvious to me how to actually run them ^_^

At a glance it looks like this will involve some js_wrapping changes which aren't as trivial so I don't think I'll try drafting a fix unless I get more free time.

Full error stack:

Uncaught Error: Expected a value of type 'List<google.maps.LatLng?>?', but got one of type 'List<dynamic>'
    at Object.throw_ [as throw] (errors.dart:248:21)
    at Object.castError (errors.dart:84:3)
    at Object.cast [as as] (operations.dart:452:10)
    at dart.NullableType.new.as (types.dart:367:9)
    at Object._callMethodUnchecked1 (js_util.dart:104:3)
    at Encoding.decodePath (google_maps_geometry.js.g.dart:32:7)
    at main$ (main.dart:11:28)
    at main.dart.bootstrap.js:272:10
    at Array.forEach (<anonymous>)
    at window.$dartRunMain (main.dart.bootstrap.js:271:32)
    at <anonymous>:1:8
    at Object.runMain (client.js:8805:21)
    at client.js:24459:19
    at _wrapJsFunctionForAsync_closure.$protected (client.js:3475:15)
    at _wrapJsFunctionForAsync_closure.call$2 (client.js:11564:12)
    at Object._asyncStartSync (client.js:3439:20)
    at main__closure4.$call$body$main__closure (client.js:24472:16)
    at main__closure4.call$1 (client.js:24398:19)
    at StaticClosure._rootRunUnary (client.js:3843:16)
    at _CustomZone.runUnary$2$2 (client.js:12970:39)
    at _CustomZone.runUnaryGuarded$1$2 (client.js:12917:14)
    at _ControllerSubscription._sendData$1 (client.js:12504:19)
    at _DelayedData.perform$1 (client.js:12686:59)
    at _PendingEvents_schedule_closure.call$0 (client.js:12735:14)
    at Object._microtaskLoop (client.js:3681:24)
    at StaticClosure._startMicrotaskLoop (client.js:3687:11)
    at _AsyncRun__initializeScheduleImmediate_internalCallback.call$1 (client.js:11440:9)
    at invokeClosure (client.js:1274:26)
    at MutationObserver.<anonymous> (client.js:1293:18)
a14n commented 2 years ago

Thanks for the report. 6f23fa6 fixes the issue. Version 6.1.1 is available with this fix.

(Side note: you can use the geo package to encode/decode paths without js-interop const PolylineCodec().encode(....) or const PolylineCodec().decode(....))

deedub-g commented 2 years ago

Thanks for the fix. Note that the cast used to fix this leads to exceptions if you try to pass the decode result into a google maps method that wants a List. At runtime you get a "InvalidValueError: not an Array" exception from within the google-maps library. It appears lists created from .cast() aren't very compatible with the js-interop. For example this error will be thrown if you try to pass the decode result into PolylineOptions().path.

I'm currently working around this by explicitly calling .toList() on the result of .decode -- resulting in a raw List opposed to the special "CastList" object that gets returned by cast: https://github.com/dart-lang/sdk/blob/b33e376857cde2dbed171e0f447e4dc792a784b7/sdk/lib/core/list.dart#L292.

I'd suggest patching.

a14n commented 2 years ago

I filed https://github.com/dart-lang/sdk/issues/49271 . Depending on the answer I'll see if I change every place a .cast() is used.