firebase-js-sdk icon indicating copy to clipboard operation
firebase-js-sdk copied to clipboard

[SDK v9] Firestore `updateDoc` generates TypeScript Error when using Mapped Types

Open HazyFish opened this issue 2 years ago • 4 comments

Describe your environment

  • Operating System version: Windows 11
  • Browser version: not relavent
  • Firebase SDK version: 9.6 (with TypeScript 4.5)
  • Firebase Product: Firestore database

Describe the problem

  • Firestore updateDoc generates TypeScript error when using Mapped Types.
  • The problem occurs only after updating to v9 modular SDK.

Steps to reproduce:

  1. Create a TS interface with a property of mapped type.
  2. Call updateDoc and pass an object of the interface created as the update data.
  3. The following TypeScript error is generated.
Type 'Preference' is not assignable to type 'AddPrefixToKeys<"ratings", { [x: string]: number | FieldValue; }>'.
                Index signature for type '`ratings.${string}`' is missing in type 'Preference'.ts(2345)

Relevant Code:

export interface Preference {
  defaultRating: number;
  ratings: { [name: string]: number };
}

const preference: Preference = { /* ... */ };

updateDoc( /* ... */ , preference);

HazyFish avatar Jan 04 '22 05:01 HazyFish

@HazyFish Can you provide a repro of what you're passing into the preference variable? I was able to compile the following code fine on my machine:

interface Preference {
    defaultRating: number;
    ratings: { [name: string]: number };
  }

const preference: Preference = {
      defaultRating: 5,
      ratings: {
        foo: 3
      }
 };

await updateDoc(doc(db,'foo/bar'), preference);

thebrianchen avatar Jan 06 '22 00:01 thebrianchen

Looks like the error occurs only when the property containing the mapped type is one or more level(s) deeper than the document data model.

export interface DocDataModel {
  preferences: Preferences;
}

interface Preferences {
  ratings: { [name: string]: number };
}

collectionRef: CollectionReference<DocDataModel> = /* ... */ // whether the collection is typed or not, error will always be produced, but with different error messages. 

update(id: string, update: DocDataModel): Promise<void> {
  return updateDoc(doc(this.collectionRef, id), update);  // error produced here
}

Error message when collectionRef is not typed:

Argument of type 'DocDataModel' is not assignable to parameter of type '{ [x: string]: any; } & AddPrefixToKeys<string, any>'.
  Type 'DocDataModel' is not assignable to type 'AddPrefixToKeys<string, any>'.
    Index signature for type '`${string}.${string}`' is missing in type 'DocDataModel'.ts(2345)

Error message when collectionRef is typed:

Argument of type 'DocDataModel' is not assignable to parameter of type '{ preferences?: FieldValue | ({ ratings?: FieldValue | { [x: string]: number | FieldValue | undefined; } | undefined; } & AddPrefixToKeys<"ratings", { [x: string]: number | ... 1 more ... | undefined; }>) | undefined; }'.
  Types of property 'preferences' are incompatible.
    Type 'Preferences' is not assignable to type 'FieldValue | ({ ratings?: FieldValue | { [x: string]: number | FieldValue | undefined; } | undefined; } & AddPrefixToKeys<"ratings", { [x: string]: number | FieldValue | undefined; }>) | undefined'.
      Type 'Preferences' is not assignable to type '{ ratings?: FieldValue | { [x: string]: number | FieldValue | undefined; } | undefined; } & AddPrefixToKeys<"ratings", { [x: string]: number | FieldValue | undefined; }>'.
        Type 'Preferences' is not assignable to type 'AddPrefixToKeys<"ratings", { [x: string]: number | FieldValue | undefined; }>'.
          Index signature for type '`ratings.${string}`' is missing in type 'Preferences'.ts(2345)

HazyFish avatar Jan 06 '22 01:01 HazyFish

@HazyFish I was able to reproduce the issue with TS v4.5. The issue isn't present on v4.4.x.

I'll leave this issue open, but we probably won't prioritize this immediately since our SDK is still on TS v4.2.2.

thebrianchen avatar Jan 07 '22 01:01 thebrianchen

I am getting the same error message.

Firebase JS SDK version 9.6.6, with TypeScript version 4.5.4.

Mine is showing when typing any object and using that for the update function.

Example:

export interface User {
  name: string;
}

const user: User = {
  name: 'Mary'
};

updateDoc( /* ... */ , user);

The same error also shows during batch updates (i.e. batch.update(/* ... */, user);

BenJackGill avatar Aug 27 '22 02:08 BenJackGill

Hello. Any update regarding this issue? Is a more recent version of typescript planned on being supported?

bigbulb avatar Oct 04 '22 01:10 bigbulb

Also running into this with the following interface used to describe the type of object I'm trying to update:

export interface Task {
  id?: string;
  title: string;
  description: string;
}

jakehockey10 avatar Oct 07 '22 01:10 jakehockey10

I am still having the same issue with Firebase 9.13 and Typescript 4.7.4 (supported by the latest firebase package). @thebrianchen are you able to replicate the issue as well with the new version?

bigbulb avatar Oct 30 '22 19:10 bigbulb

I faced the same issue before, you have to pass into the updateDoc same object in new object by spread operator.

export interface Preference {
  defaultRating: number;
  ratings: { [name: string]: number };
}

const preference: Preference = { /* ... */ };

updateDoc( /* ... */ , {...preference});

AhmedEid3 avatar Nov 05 '22 07:11 AhmedEid3