Osman
Osman

Reputation: 11

Map key is a String but returns "Object?"

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?

Upvotes: 1

Views: 921

Answers (2)

NelsonThiago
NelsonThiago

Reputation: 830

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();

Upvotes: 2

dumazy
dumazy

Reputation: 14435

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'],
  ),
];

Upvotes: 2

Related Questions