skip to Main Content

I am using firebase-admin to control a firestore database using Cloud Functions with TypeScript. If I set the type of my collection reference, I can no longer add using FieldValues. The argument types from add require a literal object matching the collection document, without any FieldValues. What is a supported pattern for using FieldValues with firebase-admin in TypeScript? Any answer using the base libraries with FieldValues will do.

Here is a minimal example with FieldValue.serverTimestamp:

import { firestore, initializeApp } from 'firebase-admin'
import { firebaseConfig } from './secret'
import { https } from 'firebase-functions'

interface User {
  id?: string
  displayName: string
  createdAt: firestore.Timestamp
}
const converter = {
  toFirestore: (data: User) => data,
  fromFirestore: (snapshot: firestore.QueryDocumentSnapshot<User>): User => {
    const data = snapshot.data()
    const doc = { id: snapshot.id, ...data }
    return doc
  }
}
initializeApp(firebaseConfig)
const db = firestore()
const usersCollectionRef = db.collection('users').withConverter(converter)
export const cloudFunction = https.onCall(async (props, context) => {
  const newUserData = {
    displayName: 'New User',
    createdAt: firestore.FieldValue.serverTimestamp()
  }
  await usersCollectionRef.add(newUserData)
  // Argument of type '{ displayName: string; createdAt: firestore.FieldValue; }' is not assignable to parameter of type 'User'.
  // Types of property 'createdAt' are incompatible.
  // Type 'FieldValue' is missing the following properties from type 'Timestamp': seconds, nanoseconds, toDate, toMillis
})

Similarly, with FieldValue.arrayUnion:

interface User {
  id?: string
  friendNames: string[]
}
const converter = {
  toFirestore: (data: User) => data,
  fromFirestore: (snapshot: firestore.QueryDocumentSnapshot<User>): User => {
    const data = snapshot.data()
    const doc = { id: snapshot.id, ...data }
    return doc
  }
}
initializeApp(firebaseConfig)
const db = firestore()
const usersCollectionRef = db.collection('users').withConverter(converter)
export const cloudFunction = https.onCall(async (props, context) => {
  await usersCollectionRef.add({
    friendNames: firestore.FieldValue.arrayUnion('BFF')
    // Type 'FieldValue' is missing the following properties from type 'string[]': length, pop, push, concat, and 29 more.

  })
})

2

Answers


  1. I think you need to define createdAt as Timestamp Type

    import type { Timestamp } from 'firebase-admin/firestore';
    
    interface User {
      displayName: string
      createdAt: Timestamp
    }
    

    I believe this should fix the problem

    Login or Signup to reply.
  2. Try this

    import * as admin from 'firebase-admin'
    import { Timestamp } from 'firebase-admin/firestore'
    
    interface UserType {
      id?: string
      displayName: string
      createdAt: Timestamp
      // update
      friends: string[]
    }
    
    ....
    
    // creates a firestore hanlder
    export const firestore = Object.assign(
      () => {
        return admin.firestore()
      }, {
        doc: <T>( path: string ) => {
          return admin.firestore()
            .doc( path )
            .withConverter<T>( converter<T>() )
        },
        collection: <T>( path: string ) => {
          return admin.firestore()
            .collection( path )
            .withConverter<T>( converter<T>() )
        },
        // update
        fieldValue: admin.firestore.FieldValue
      } )
    // typed converter
    const converter = <T>() => ( {
      toFirestore: ( data: any ) => data,
      fromFirestore: ( doc: any ) => {
        return {
           ...doc.data(),
           id: doc.id
        } as T
      }
    } )
    

    then use it like this:

    import {firestore} from 'some/place'
    
    ...
    
    // you can now have types while setting and getting data
    const usersRef = firestore.collection<UserType>('/users')
    await userRef.add({
      displayName: 'New User',
      // update
      createdAt: firestore.fieldValue.serverTimestamp(),
      friends: firestore.fieldValue.arrayUnion('FRIEND_NAME')
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search