Search code examples
angularfirebasegoogle-cloud-platformgoogle-cloud-firestoreangular13

Why am I obtaining this "'id' is specified more than once..." error trying to spread out id and data() from the result returned by Firestore?


it is passed a lot of time from the last time that I worked on Angular and Firebase and I am finding the following simple problem trying to use AngularFire 2 in order to retrieve the entire objects from a Firestore collection (it means the document ID + the document data that must be put into a model object).

So this is my situation.

First of all this is my package.json file:

{
  "name": "fintness-tracker",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~13.3.0",
    "@angular/cdk": "^13.3.8",
    "@angular/common": "~13.3.0",
    "@angular/compiler": "~13.3.0",
    "@angular/core": "~13.3.0",
    "@angular/flex-layout": "^13.0.0-beta.38",
    "@angular/forms": "~13.3.0",
    "@angular/material": "^13.3.8",
    "@angular/platform-browser": "~13.3.0",
    "@angular/platform-browser-dynamic": "~13.3.0",
    "@angular/router": "~13.3.0",
    "angularfire2": "^5.4.2",
    "firebase": "^7.24.0",
    "hammerjs": "^2.0.8",
    "rxjs": "~7.5.0",
    "rxjs-compat": "^6.6.7",
    "tslib": "^2.3.0",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~13.3.6",
    "@angular/cli": "~13.3.6",
    "@angular/compiler-cli": "~13.3.0",
    "@types/jasmine": "~3.10.0",
    "@types/node": "^12.11.1",
    "jasmine-core": "~4.0.0",
    "karma": "~6.3.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.1.0",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "~1.7.0",
    "typescript": "~4.6.2"
  }
}

Then I have this simple Exercise model interface that will map a Firebase document:

export interface Exercise {
    id: string;
    name: string;
    duration: number;
    calories: number;
    date?: Date;
    state?: 'completed' | 'cancelled' | null;
}

And finally my NewTrainingComponent Angular component class, in its ngOnInit()

import { Component, OnInit, EventEmitter, Output } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Exercise } from '../exercise.model';
import { TrainingService } from '../training.service';
import { AngularFirestore } from 'angularfire2/firestore';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';



@Component({
  selector: 'app-new-training',
  templateUrl: './new-training.component.html',
  styleUrls: ['./new-training.component.css']
})
export class NewTrainingComponent implements OnInit {

  @Output()
  trainingStart:EventEmitter<void> = new EventEmitter<void>();

  //exercises: Exercise[] = [];
  exercises: Observable<any>;

  constructor(private trainingService: TrainingService,
              private db: AngularFirestore) { }

  ngOnInit(): void {
    //this.exercises = this.trainingService.getAvailableExercises();

    //this.exercises = this.db
    this.db
      .collection("availableExercises")
      .snapshotChanges()
      .pipe(
        map((docArray) => {
          return docArray.map((doc) => {
            return {
              id: doc.payload.doc.id,
              ...(doc.payload.doc.data() as Exercise),
            };
          });
        })
      )
      .subscribe(result => {
        console.log(result);

      });

    /*
    this.db.collection('availableExercises').valueChanges().subscribe(result => {
      console.log(result);
    })
    */
  }

  onStartTraining(form: NgForm) {
    this.trainingService.startExercise(form.value.exercise);
  }

}

What is the problem?

The problem is that when I try to create my model object in this way:

return {
  id: doc.payload.doc.id,
  ...(doc.payload.doc.data() as Exercise),
};

it give me the following error on the id property on my IDE:

'id' is specified more than once, so this usage will be overwritten.ts(2783)

Compiling I obtain the same error:

Error: src/app/training/new-training/new-training.component.ts:38:15 - error TS2783: 'id' is specified more than once, so this usage will be overwritten.

38               id: doc.payload.doc.id,
                 ~~~~~~~~~~~~~~~~~~~~~~

  src/app/training/new-training/new-training.component.ts:39:15
    39               ...(doc.payload.doc.data() as Exercise),
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    This spread always overwrites this property.


Error: src/app/training/new-training/new-training.component.ts:38:15 - error TS2783: 'id' is specified more than once, so this usage will be overwritten.

38               id: doc.payload.doc.id,
                 ~~~~~~~~~~~~~~~~~~~~~~

  src/app/training/new-training/new-training.component.ts:39:15
    39               ...(doc.payload.doc.data() as Exercise),
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    This spread always overwrites this property.




✖ Failed to compile.

If I remove this property and I use:

return {
  //id: doc.payload.doc.id,
  ...(doc.payload.doc.data() as Exercise),
};

I obtain no error but when the console.log() print out my result it doesn't contains the id property.

Why? What is wrong with my code? What am I missing? How can I try to fix it?


Solution

  • This is because you have an id property in your Exercice interface.

    Switching the order as follows should do the trick, according to this SO answer (I didn't test it):

    return {
      ...(doc.payload.doc.data() as Exercise),
      id: doc.payload.doc.id
    };