1

I have the following List of Maps:

var questions = [
  {
    'questionText': 'What is your favorite color?',
    'answers': ['Black', 'Green', 'Red', 'White'],
  },
  {
    'questionText': 'What is your favorite animal?',
    'answers': ['Pig', 'Goat', 'Lion', 'Baboon'],
  },
  {
    'questionText': 'What is your favorite number?',
    'answers': ['1', '2', '3', '4'],
  },
  {
    'questionText': 'What is your favorite game console?',
    'answers': ['Xbox', 'Playstation', 'Nintendo', 'PC'],
  },
  {
    'questionText': 'What is your favorite car model?',
    'answers': ['Nissan', 'Toyota', 'Ford', 'Honda'],
  },
];

I have an Example function that takes String type Arguments. If I wanted to use the keys one of the maps as that argument as such:

ExampleFunction(questions[1]['questionText']);

I get the following error:

The argument type 'Object?' can't be assigned to the parameter type 'String'.

I understand that using the map operator "[ ]" produces a nullable type according to documentation. It says to use an exclamation mark as follow to make it non-nullable:

ExampleFunction(questions[1]['questionText']!);

But this just produces the following error, this time without the explanation "?" mark:

The argument type 'Object' can't be assigned to the parameter type 'String'.

When I hover over the list it gives me:

List<Map<String, Object>>

Why are the keys appearing as an object when the only types I have in each map is String Keys, and List Answers?

Osman
  • 11
  • 1
  • You have mixed types in your maps. Eventhough the value for key `questionText` is indeed a `String`, the value for key `answers` is a something like a `List`. So, for a consistent typing, the map the must be of `Map` where `T` is a common supertype of `String` and `List` which is `Map` – derpirscher Jun 21 '21 at 12:54
  • btw, it's [working](https://dartpad.dev/edd6a12871c32e0ae2b745e748c74e01?null_safety=true) ¯\_(ツ)_/¯ – blackkara Jun 21 '21 at 12:58
  • 1
    @blackkara yes, but the type is still `Object?`. the `print` function just takes an `Object?` and calls the `toString()` function on that, which is the string itself for an object of type `String` – dumazy Jun 21 '21 at 13:00
  • 2
    @blackkara Yeah, but only for `print` because print also accepts `Object`s and calls `toString()` internally in that specific overload. But you can't pass an `Object` into a function, that expects a `String` (and only a String) – derpirscher Jun 21 '21 at 13:01
  • yep good point! – blackkara Jun 21 '21 at 13:05
  • Thanks Everyone. You guys helped alot. – Osman Jun 22 '21 at 03:25

2 Answers2

2

The Map has multiple value types: String for the questionText and List<String> for the answers. The closest matching type for those two is Object.

You can either specify the type with the as keyword:

questions[1]['questionText'] as String

or create a specific class

class Question {
  final String questionText;
  final List<String> answers;

  Question({
    required this.questionText,
    required this.answers,
  });
}

var questions = [
  Question(
    questionText: 'What is your favorite color?',
    answers: ['Black', 'Green', 'Red', 'White'],
  ),
];
dumazy
  • 13,857
  • 12
  • 66
  • 113
2

The problem is you don't have Map<String, String>.

{
    'questionText': 'What is your favorite color?',  -> <String, String>
    'answers': ['Black', 'Green', 'Red', 'White'],  -> <String, List>
  }

Because the data inside the Map can be a String or a List the Object is assigned -> Map<String, Object>.

You can convert to String using toString()

questions[1]['questionText']!.toString();

Or you can create a class called question:

class Question{
   String questionText;
   List<String> answers;

  Question(this.questionText, this.answers);
  
  factory Question.fromMap(Map) {
   return Question(map[questionText], map[answers]);
}

Map<String, dynamic> toMap() {
  return {
  "questionText": this.questionText,
   "answers": this.answers,
  }
 }

}

With the Question class you can create a Question from a map Question.fromMap(questions[0]). And Convert to Map myQuestion.

Question question = Question("question", ["answer1", "answer2"]); 
ExampleFunction(question.questionText);

or

Question question = Question.fromMap(myQuestionMap);
ExampleFunction(question.questionText);

and convert to map

Map mapQuestion = question.toMap();
NelsonThiago
  • 802
  • 7
  • 12