Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add typings to firebase collection query

I have a function like:

async queryAll(): Promise<Product[]> {
  const response = await this.firestore.collection('products').get();
  return response.docs.map(a => a.data());
}

And getting error:

Type 'DocumentData[]' is not assignable to type 'Product[]'. Type 'DocumentData' is missing the following properties from type 'Product': id, name

How can I add proper return typings for this method?

What can I see in firebase/index.ts.d, get function types looks like (I am using npm firebase package):

get(options?: GetOptions): Promise<QuerySnapshot<T>>;

But not sure how to apply this to my code.

like image 320
bsekula Avatar asked Feb 04 '20 20:02

bsekula


People also ask

How do you get Boolean on firestore?

valueof(str) method, it will return you a Boolean object and to see what it contains you will need to use booleanValue() method of the Boolean class as per Official Documentation Javadoc.

How do I add a field to an existing document in firestore?

Build a DocumentReference to the document you want to update, then use the update() method on the DocumentReference to indicate only the fields to be added or changed. Pass it an object with only properties that match the fields to add or change.


2 Answers

I have found solution, need to use withConverter in order to add typings when retrieving data from firestore collections

Added working example, result from dbQuery function should have proper type i.g. Product[]

import firebase from 'firebase';
import { firebaseConfig } from '../firebaseConfig';

export interface Product {
  name: string;
}

export const productConverter = {
  toFirestore(product: Product): firebase.firestore.DocumentData {
    return { name: product.name };
  },

  fromFirestore(
    snapshot: firebase.firestore.QueryDocumentSnapshot,
    options: firebase.firestore.SnapshotOptions
  ): Product {
    const data = snapshot.data(options)!;
    return { name: data.name }
  }
};

async function dbQuery() {
  firebase.initializeApp(firebaseConfig);
  const db = firebase.firestore();
  const response = await db.collection("products").withConverter(productConverter).get();
  const result = response.docs.map(doc => {
    const data = doc.data();
    return data;
  });

  return result; // result type is Product[]
}
like image 173
bsekula Avatar answered Sep 21 '22 06:09

bsekula


I find its very simple to use TypeScript's Type assertions feature for this.

await db.collection('products').get() as firebase.firestore.QuerySnapshot<Product>;

For single documents:

await db.collection('products').doc('12345').get() as firebase.firestore.DocumentSnapshot<Product>;

For snapshots:

db.collection('products')
  .onSnapshot((snapshot: firebase.firestore.QuerySnapshot<Product>) => {
    for (const doc of snapshot.docs) {
      const product = doc.data();
    }
  });

When you call data() on the document snapshot, its type will be of Product.

like image 34
Jon Sakas Avatar answered Sep 22 '22 06:09

Jon Sakas