How can data be cast when using patterns for destructuring in Dart?

65 views Asked by At

I encountered a TypeError with data received from an API. To simulate the issue clearly, I have provided a code example below:

   //This is mock data to simulate the API.
   //The length of the array or the keys is not specified
   // We only know that it should be a List<Map<String, dynamic>>
    List<dynamic> dat2 = [{"id1": 'food',},{'id2': "car"}];
    var data = {"types": dat2, "clientId": "Id"}

;

the code:

         if (data case {
                   //how I can cast it to List<Map<String, dynamic>> here without extra code?
                  "types": List<Map<String, dynamic>> types,
                  "clientId": String clientId}) 
                       {
                          debugPrint('types:$types, clientId: $clientId');
                        } else {
                           debugPrint('Error');
                                }

The error occurs within the "types" argument. How can I cast it appropriately within the if condition to resolve this?

3

There are 3 answers

0
Pratik Lakhani On

Try this!

List<dynamic> dat2 = [
  {
    "id1": 'food',
  },
  {'id2': "car"}
];
dynamic data = {"types": dat2, "clientId": "Id"};

if (data is Map<String, dynamic> &&
    data.containsKey("types") &&
    data["types"] is List<dynamic>) {
  List<Map<String, dynamic>> types = [];
  for (var item in data["types"]) {
    if (item is Map<String, dynamic>) {
      types.add(Map<String, dynamic>.from(item));
    }
  }
  String clientId = data["clientId"];
  debugPrint('types:$types, clientId: $clientId');
} else {
  debugPrint('Error');
}

If it's helpful to you, then accept the answer and don't forget to upvote.

0
Dan R On

In the first line you declare that dat2 is of type List<dynamic> which does not match the more specific List<Map<String, dynamic>>.

It would work by declaring dat2 as:

List<Map<String, dynamic>> dat2 = [
  {'id1': 'food'},
  {'id2': 'car'}
];
var data = {'types': dat2, 'clientId': 'Id'};

void main() {
   
  if (data
      case {
        'types': List<Map<String, dynamic>> types,
        'clientId': String clientId
      }) {
    print('types:$types, clientId: $clientId');
  } else {
    print('Error with $data');
  }
}

Running the program results in the following output:

$ dart main.dart
types:[{id1: food}, {id2: car}], clientId: Id

If dat2 has to be of type List<dynamic> then you will have to use the same type in the pattern:

List<dynamic> dat2 = [
  {'id1': 'food'},
  {'id2': 'car'}
];
var data = {'types': dat2, 'clientId': 'Id'};

void main() {
  if (data
      case {
        'types': List<dynamic> types,
        'clientId': String clientId
      }) {
    print('types:$types, clientId: $clientId');
  } else {
    print('Error with $data');
  }
1
Randal Schwartz On

If you really want to do this with pattern matching, I think you have to do it in two stages. I got this to act as expected, hopefully it can be a starting point for you:

void main(List<String> arguments) {
  final dat2 = <dynamic>[
    {
      'id1': 'food',
    },
    {'id2': 'car'},
  ];
  final data = {'types': dat2, 'clientId': 'Id'};
  final result = switch (data) {
    {
      'types': final List<dynamic> types,
      'clientId': final String clientId,
    } =>
      switch (types) {
        [
          {'id1': final String id1},
          {'id2': final String id2},
        ] =>
          (id1, id2, clientId),
        final w => 'was w $w',
      },
    final v => 'was v $v',
  };
  print(result);
}

This outputs (food, car, Id).