What is causing this TypeScript error to be raised by this statement?

Can you explain why the following statement is throwing a type error?

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

The error message states:

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

This code snippet uses the spread operator to extract three elements of an object, leaving id provided by the second operand.

The technologies being used are Vue 3.0.0, firebase 9.0.2, and typescript 4.1.5

Below is the complete component for reference:

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

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'm still learning TypeScript, so any insights would be greatly appreciated. Thank you!

Answer №1

According to @TJCrowder, it is important to understand what the data() method returns. The method returns an object of type DocumentData, and Typescript may not accurately identify its contents. To specify that the object will be of type Chat, a type assertion can be used like this:

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

However, there is a risk of mistyping documents that do not exist (when doc.exists === false - typically encountered when working with a DocumentReference rather than queries). Instead of asserting the type on the line containing doc.data(), the type of the CollectionReference used in the query can be asserted. This approach applies equally to a DocumentReference. Typescript ensures proper handling of cases where a document does not exist first.

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

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

For further information on Type Assertion in Typescript, refer to the language's documentation.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How to eliminate certain elements from the DOM in Angular 5

I'm facing a minor issue in my Angular/Typescript project that I can't seem to resolve. I am still new to these technologies and struggling with removing certain DOM elements. The content is auto-generated with specific CSS classes, and unfortuna ...

The specified type argument is not compatible with the ObservableInput<any> type

Struggling with an issue where the argument type (key:string) => Observable | PayloadType | is causing problems when trying to assign it to a parameter of type '(value: string, index: number) => ObersvableInput' return action$.pipe( fil ...

Finding the origin of a request in Node.js using Express.js

In my firebase functions built with nodejs, I have utilized an express app to develop a sophisticated API within a single firebase function. Here is an example of how it looks: import * as functions from 'firebase-functions'; const express = req ...

Real-time monitoring within a callback function in Angular 5

I need to ensure that a specific callback is executed only after receiving a response, starting from the line this.groupDefaultExpanded = -1; onwards. loadLoginDetails() { this.derivativeSpecService.getDerivativeDetails().subscribe( res => ...

Utilizing NPM Workspaces to efficiently distribute TypeScript definition files (`*.d.ts`) across multiple workspaces

In my TypeScript monorepo utilizing NPM Workspaces, I have two packages: A and B. Package B requires type definitions from package A. To accomplish this, I included a reference to A's definition file in the tsconfig.json of package B. However, somet ...

Can you explain the significance of syntax in sample code (typescript, react)?

const sampleFunction: (inputString: string) => string = inputString => { return inputString.split(""); } I'm a bit confused about the code below and would appreciate some clarification. I understand that only "string" as a type is accepted, b ...

The function Getter is expected, but an error has occurred with "getters.doubleCounter" returning a value of 20 in VUEX

Currently, I am diving into the world of Vuex and encountering some challenges along the way. In my attempt to create a getter on my vuex instance, I am facing an error when trying to display data from one of my components: The getter should be a functi ...

What is the reason behind TypeScript prohibiting the assignment of a className property to a context provider?

Embarking on my first journey with TypeScript, I am in the process of reconfiguring a React application (originally built with create-react-app) to use TS. Specifically, I am working with function components and have introduced a global context named Order ...

Is it possible to instruct Vue to prioritize the inherited class over others?

I have a situation in my component where I need Vue to disregard the existing class and instead use the inherited class, but only if it is of the same type as the inherited class. Let me illustrate with an example: Consider a button component like this M ...

"Exploring the Synchronization Feature in Vue.js 2.3 with Element UI Dialog Components

Recently, I've encountered some changes while using Element UI with the latest release of Vue.js 2.3 In my project, a dialog should only be displayed if certain conditions are met: private.userCanManageUsers && private.pendingUsers.length > ...

How to select an unwrapped element using the v-popover component

The v-popover component is commonly used by wrapping an element inside of it, like so: <v-popover offset="0" placement="right"> <span>My awesome span</span> <template slot="popover">My awesome popov ...

Initiate the input change event manually

Struggling with creating a custom counter input component where the input value is controlled by custom increment/decrement buttons. Desired output: https://i.sstatic.net/oYl1g.png Content projection will be used to expose the input for form usage and a ...

Tips for refreshing the Vuex store to accommodate a new message within a messageSet

I've been working on integrating vue-socket.io into a chat application. I managed to set up the socket for creating rooms, but now I'm facing the challenge of displaying messages between chats and updating the Vuex store to show messages as I swi ...

Is it possible to dynamically close the parent modal based on input from the child component?

As I follow a tutorial, I am working on importing the stripe function from two js files. The goal is to display my stripe payment in a modal. However, I am unsure how to close the modal once I receive a successful payment message in the child. Below are s ...

Issue 1068: Attribute not found within angular 2 (Ahead of Time Compilation)

I am currently learning Angular 2 and trying to create a "User Register" form. However, I encountered an error stating "Property does not exist on type" during Phone number validation. I am using both JIT and AOT compilers. With the JIT compiler, my user ...

Utilizing @ngrx/router-store in a feature module: A comprehensive guide

The NGRX documentation for Router-Store only showcases an example with .forRoot(). Upon experimenting with .forFeature(), I realized that this static method does not exist. I am interested in defining certain actions and effects to be utilized within my f ...

TypeScript and Angular: Harnessing the Power of Directive Dependency Injection

There are multiple approaches to creating Angular directives in TypeScript. One elegant method involves using a static factory function: module app { export class myDirective implements ng.IDirective { restrict: string = "E"; replace: ...

A beginner's guide to utilizing querySelectorAll in VueJS

I want to track GA events using Nuxt, but I'm facing an issue where only the first event is being returned due to the use of document.querySelector instead of querySelectorAll. I've tried using the spread operator and a for() loop without success ...

What is the best way to calculate the number of days between today's date and the end of the current month using Moment.js?

Here's the current code snippet I am working with: const moment = require('moment') const m = moment const currDay = m().format('D') const dayOfWeek = m().format('dddd') const daysInMonth = m().daysInM ...

retrieve essential data from Firebase using JavaScript

Currently, I am utilizing the get() method to retrieve data in my React Native application. Here is the code snippet that I am using: firebase .firestore() .collection("users") .doc("test") .get() .then(response => { console.log(respo ...