CSFrequency / react-firebase-hooks

React Hooks for Firebase.
Apache License 2.0
3.55k stars 304 forks source link

Is it possible to add a type to the data returned by useCollectionData hook? #285

Closed JamesBrightman closed 1 year ago

JamesBrightman commented 1 year ago

I would like to add a type to the data returned by the useCollectionData firestore hook. Currently I am using it like so -

import React from "react"
import {collection, query} from "firebase/firestore"
import {useCollectionData} from "react-firebase-hooks/firestore"
import { db } from "./firebase-setup/firebase"

export interface EntryObject {
  rating: number
}

export const App = () => {

  const [data, loading, error] = useCollectionData(
    query(collection(db, "entries"))
  );

  console.log(data, loading, error)

  return (
    <div>
      {(data as EntryObject[])?.map((ele: EntryObject) => {return <div>{ele.rating}</div>})}
    </div>
  )
}

I would like the data const to be of type EntryObject[]. Currently I am declaring this at the start of the map function, which does work, but ideally I'd know the type of data before mapping it. Is this currently possible?

My firebase initialization file is -

import {getFirestore} from "firebase/firestore";
import "firebase/storage";
import "firebase/auth";
import {initializeApp} from "firebase/app"

const firebaseConfig = {
  apiKey: ---
  authDomain: ---
  projectId: ---
  storageBucket: ---
  messagingSenderId: ---
  appId: ---
  measurementId: ---
};

const app = initializeApp(firebaseConfig);

const db = getFirestore(app);

export {db}

Package versions

"firebase": "^9.15.0", "react-firebase-hooks": "^5.1.1",

JamesBrightman commented 1 year ago

I found a way to do this using FirestoreDataConverter which I believe is the currently accepted method for adding type to return hook return data.

firestoreDataConverters.ts

import { FirestoreDataConverter, DocumentData, QueryDocumentSnapshot, SnapshotOptions, Timestamp } from "firebase/firestore";

export type entry = {
    id?: string,
    createdAt: Timestamp,
    rating: number
  }

  export const entryConverter: FirestoreDataConverter<entry> = {
    toFirestore: (entryData: entry): DocumentData => {
        return entryData;
    },
    fromFirestore: (snapshot: QueryDocumentSnapshot, options: SnapshotOptions): entry => {
        const {rating, createdAt} = snapshot.data(options);
        return {rating, createdAt, id: snapshot.id};
    },
};

Changes in original App.tsx

const [data, loading, error] = useCollectionData<entry>(
    query(collection(db, "entries")).withConverter(entryConverter)
  );

Now data will be typed as entry :)