David Zapata
David Zapata

Reputation: 29

The operator '[]' isn't defined for the type 'Object'. Try defining the operator '[]'. Error when trying to get data from Firestore

I am trying to retrieve data from a document stored in Firestore. I've tried several times to find a way to fix this error but haven't been able to find something useful.

Here's my code.

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

class GetUserName extends StatelessWidget {
  final String documentId;

  GetUserName(this.documentId);

  @override
  Widget build(BuildContext context) {
    CollectionReference users = FirebaseFirestore.instance.collection('Drivers');

    return FutureBuilder<DocumentSnapshot>(
      future: users.doc(documentId).get(),
      builder:
          (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {

        if (snapshot.hasError) {
          return Text("Something went wrong");
        }

        if (snapshot.hasData && !snapshot.data!.exists) {
          return Text("Document does not exist");
        }

        if (snapshot.connectionState == ConnectionState.done) {
          Object? data = snapshot.data!.data();
          return Text(data!['username']);
        }

        return Text("loading");
      },
    );
  }
}

The error happens when I try to retrieve 'username' from data.

Thanks for your help

Upvotes: 0

Views: 390

Answers (2)

aimene chikhi
aimene chikhi

Reputation: 11

snapshot.data()['username'] => snapshot['username']

Upvotes: 0

cameron1024
cameron1024

Reputation: 10136

The problem lies in the difference between Object and dynamic.

In Dart, Object? is the "top type", which essentially means: "all values are Object?s".

dynamic is often used in a similar situation (when you don't know the type of the data you're working with, and don't want the type system complaining at you), but it has a very different meaning. In short, it means "turn off type checking because I know what I'm doing".

The main difference between Object? and dynamic comes down to their members.

Object? has a few members defined on it:

  • toString()
  • runtimeType
  • hashCode
  • noSuchMethod(Invocation invocation)

All objects share these members, because all objects are Object?s. If you have a value of static type Object?, these are the only 4 members that Dart can guarantee exist, so these are the only ones you are allowed to call (just like you'll get an error if you try to call "some string".notARealMethod()).

dynamic does the opposite: it assumes all possible members exist and never gives you a warning for any access, so for example:

String s = "hello";
s.notARealMethod();  // compile time error
final d = s as dynamic;  // explicitly cast to dynamic
d.notARealMethod();  // now throws at runtime

So, going back to your code, you have this:

Object? data = snapshot.data!.data();
return Text(data!['username']);

data is an Object?, so data! is an Object, and as we saw before, the only 4 members on Object are: toString(), runtimeType, hashCode and noSuchMethod(Invocation invocation). So Dart will complain because it can't guarantee that [] exists.

To fix this:

  1. use dynamic instead of Object?. It won't give you a compile error, but it will throw at runtime if the value ends up not having the [] operator (although because this is coming from firestore, this is a safe bet)

  2. use a type check (and make use of type promotion):

Object? data = snapshot.data;
if (data is Map<String, dynamic>) {
  // dart now knows that data is a Map, and now you can safely call Map methods (e.g. [])
  return Text(data['username']);
}

throw "not a map";  
// or 
return SomeErrorWidget();

Upvotes: 4

Related Questions