Richard Johnson
Richard Johnson

Reputation: 561

Dart 2.X List.cast() does not compose

The upcoming Dart 2.X release requires strong typing. When working with JSON data we must now cast dynamic types to an appropriate Dart type (not a problem). A related question Ignoring cast fail from JSArray to List<String> provides the answer to use the .cast<String>() function. Also a recent group messages says the same: Breaking Change: --preview-dart-2 turned on by default.

The problem is that the .cast() function doesn't seem to compose. This original code when compiled using DDC and run in the Chrome browser:

Map<String, dynamic> json = { "data": ["a", "b", "c"] };
List<String> origBroken = json["data"].map( (s) => s.toUpperCase() ).toList();

Now receives the runtime warning (which will soon be an error)

Ignoring cast fail from JSArray to List<String>

So I add the .cast<String>() as the documentation and related link suggest and still receive the warning:

List<String> docFixBroken = json["data"].cast<String>().map( (s) => s.toUpperCase() ).toList();
List<String> alsoBroken = List.from( (json["data"] as List).cast<String>() ).map( (s) => s.toUpperCase() ).toList();

The code that doesn't give the warning requires a temporary variable (and also seems to be able to skip the explicit cast):

List<String> temp = json["data"];
List<String> works = temp.map( (s) => s.toUpperCase() ).toList();

So how can I write the cast and map as a single composed expression? The reason I need it as a single expression is that this expression is being used in an initializer list to set a final class variable.

Upvotes: 7

Views: 9569

Answers (1)

matanlurey
matanlurey

Reputation: 8614

I wrote Ignoring cast fail from JSArray to List<String>, so let me try and help here too!

So I add the .cast<String>() as the documentation and related link suggest and still receive the warning:

List<String> docFixBroken = json["data"].cast<String>().map( (s) => s.toUpperCase() ).toList();
List<String> alsoBroken = List.from( (json["data"] as List).cast<String>() ).map( (s) => s.toUpperCase() ).toList();

Unfortunately, List.from does not persist type information, due to the lack of generic types for factory constructors (https://github.com/dart-lang/sdk/issues/26391). Until then, you should/could use .toList() instead:

(json['data'] as List).toList()

So, rewriting your examples:

List<String> docFixBroken = json["data"].cast<String>().map( (s) => s.toUpperCase() ).toList();
List<String> alsoBroken = List.from( (json["data"] as List).cast<String>() ).map( (s) => s.toUpperCase() ).toList();

Can be written as:

List<String> notBroken = (json['data'] as List).cast<String>().map((s) => s.toUpperCase()).toList();

Hope that helps!

Upvotes: 13

Related Questions