maxweld
maxweld

Reputation: 239

Why does this statement throw a typescript error?

The following statement throws a type error. Why?

const x: Chat = { ...doc.data(), id: doc.id }

The error is:

Type '{ id: string; }' is missing the following properties from type 'Chat': message, name, createdAt ts(2739)

The spread operand provides three elements of the object, and the id is provided by the second operand.

I am using Vue 3.0.0, firebase 9.0.2 and typescript 4.1.5

here is the whole component:

import { ref } from 'vue'
import { projectFirestore, Timestamp } from '@/firebase/config'
// import Chat from '@/types/Chat'

interface Chat {
  id?: string
  message: string
  name: string | null
  createdAt: Timestamp
}

import {
  collection as collect,
  query,
  orderBy,
  onSnapshot,
} from 'firebase/firestore'

const getCollection = (collection: string) => {
  const documents = ref<Chat[]>()
  const error = ref<string>()
  try {
    const q = query(
      collect(projectFirestore, collection),
      orderBy('createdAt', 'desc')
    )
    const unsubscripe = onSnapshot(q, (querySnapshot) => {
      const results: Chat[] = []
      querySnapshot.forEach((doc) => {
        const x: Chat = { ...doc.data(), id: doc.id }
        doc.data().createdAT && results.push(x)
      })
      documents.value = results
    })
  } catch (err) {
    if (err instanceof Error) {
      error.value = err.message
    } else {
      throw Error('Unknown Error')
    }
  }
  return { documents, error }
}

export default getCollection

I am new to typescript, but this does seem strange. Thanks in advance

Upvotes: 2

Views: 2288

Answers (1)

Dharmaraj
Dharmaraj

Reputation: 50920

As @TJCrowder commented, you can check what the data() method returns. It returns object of type DocumentData and Typescript doesn't really know what the contents are. You can try using a type assertion like this and specify that the object will be of type Chat:

const x = { ...doc.data(), id: doc.id } as Chat

However, this can lead to mistyping documents that don't exist (when doc.exists === false - usually found when working with a DocumentReference rather than queries). Instead of asserting the type on the line with doc.data(), you can assert the type of the CollectionReference that you used in the query instead. This works the same for a DocumentReference too. Typescript will make sure that you've properly handled the case where a document doesn't exist first.

collect(projectFirestore, collection) as CollectionReference<Chat>
// ...

// x will be a Chat object when `doc.exists === true` (which it is in queries)
const x = { ...doc.data(), id: doc.id }

You can read more about Type Assertion in Typescript's documentation.

Upvotes: 3

Related Questions