From 89d788b4b41d307f8a829dfa0bcf4f280bf02029 Mon Sep 17 00:00:00 2001 From: KingDarBoja <30560560+KingDarBoja@users.noreply.github.com> Date: Fri, 11 Sep 2026 13:44:24 -0500 Subject: [PATCH 1/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20tap=20depr?= =?UTF-8?q?ecation=20cleanup.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- performance/index.ts | 84 +++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/performance/index.ts b/performance/index.ts index 0e05cd2..69786a1 100644 --- a/performance/index.ts +++ b/performance/index.ts @@ -50,12 +50,10 @@ const trace$ = (traceId: string) => { export const trace = (name: string) => (source$: Observable) => new Observable((subscriber) => { const traceSubscription = trace$(name).subscribe(); return source$.pipe( - tap( - () => traceSubscription.unsubscribe(), - () => { - }, - () => traceSubscription.unsubscribe(), - ), + tap({ + next: () => traceSubscription.unsubscribe(), + complete: () => traceSubscription.unsubscribe(), + }), ).subscribe(subscriber); }); @@ -73,14 +71,16 @@ export const traceUntil = ( options?: { orComplete?: boolean }, ) => (source$: Observable) => new Observable((subscriber) => { const traceSubscription = trace$(name).subscribe(); - return source$.pipe( - tap( - (a) => test(a) && traceSubscription.unsubscribe(), - () => { - }, - () => options && options.orComplete && traceSubscription.unsubscribe(), - ), - ).subscribe(subscriber); + return source$ + .pipe( + tap({ + next: (a) => test(a) && traceSubscription.unsubscribe(), + complete: () => + options && + options.orComplete && + traceSubscription.unsubscribe(), + }), + ).subscribe(subscriber); }); /** @@ -98,23 +98,27 @@ export const traceWhile = ( options?: { orComplete?: boolean }, ) => (source$: Observable) => new Observable((subscriber) => { let traceSubscription: Subscription | undefined; - return source$.pipe( - tap( - (a) => { - if (test(a)) { - traceSubscription = traceSubscription || trace$(name).subscribe(); - } else { - if (traceSubscription) { - traceSubscription.unsubscribe(); - } - traceSubscription = undefined; + return source$ + .pipe( + tap({ + next: (a) => { + if (test(a)) { + traceSubscription = + traceSubscription || trace$(name).subscribe(); + } else { + if (traceSubscription) { + traceSubscription.unsubscribe(); } - }, - () => { - }, - () => options && options.orComplete && traceSubscription && traceSubscription.unsubscribe(), - ), - ).subscribe(subscriber); + traceSubscription = undefined; + } + }, + complete: () => + options && + options.orComplete && + traceSubscription && + traceSubscription.unsubscribe(), + }), + ).subscribe(subscriber); }); /** @@ -126,13 +130,9 @@ export const traceWhile = ( export const traceUntilComplete = (name: string) => (source$: Observable) => new Observable((subscriber) => { const traceSubscription = trace$(name).subscribe(); return source$.pipe( - tap( - () => { - }, - () => { - }, - () => traceSubscription.unsubscribe(), - ), + tap({ + complete: () => traceSubscription.unsubscribe(), + }), ).subscribe(subscriber); }); @@ -145,12 +145,8 @@ export const traceUntilComplete = (name: string) => (source$: Observabl export const traceUntilFirst = (name: string) => (source$: Observable) => new Observable((subscriber) => { const traceSubscription = trace$(name).subscribe(); return source$.pipe( - tap( - () => traceSubscription.unsubscribe(), - () => { - }, - () => { - }, - ), + tap({ + complete: () => traceSubscription.unsubscribe(), + }), ).subscribe(subscriber); }); From 98905a573e49a72cb514213bd6d1f326fc51480f Mon Sep 17 00:00:00 2001 From: KingDarBoja <30560560+KingDarBoja@users.noreply.github.com> Date: Fri, 11 Sep 2026 13:50:43 -0500 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20types:=20storage=20?= =?UTF-8?q?return=20type=20for=20getMetadata=20function.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- storage/index.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/storage/index.ts b/storage/index.ts index 9dad2d8..5bb2a78 100644 --- a/storage/index.ts +++ b/storage/index.ts @@ -7,14 +7,23 @@ import { import {Observable, from} from 'rxjs'; import {map, shareReplay} from 'rxjs/operators'; -import type {UploadTaskSnapshot, StorageReference, UploadMetadata, StringFormat, UploadTask, UploadResult} from 'firebase/storage'; +import type { + UploadTaskSnapshot, + StorageReference, + UploadMetadata, + StringFormat, + UploadTask, + UploadResult, + FullMetadata, + StorageError, +} from 'firebase/storage'; export function fromTask(task: UploadTask): Observable { return new Observable((subscriber) => { let lastSnapshot: UploadTaskSnapshot | null = null; let complete = false; let hasError = false; - let error: any = null; + let error: StorageError | null = null; const emit = (snapshot: UploadTaskSnapshot) => { lastSnapshot = snapshot; @@ -74,9 +83,13 @@ export function getDownloadURL(ref: StorageReference): Observable { return from(_getDownloadURL(ref)); } -// TODO: fix storage typing in firebase, then apply the same fix here -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function getMetadata(ref: StorageReference): Observable { +/** + * Retrieves the metadata for a given storage reference. + * + * @param ref The storage reference for which to retrieve metadata. + * @returns An observable that emits the metadata for the given reference. + */ +export function getMetadata(ref: StorageReference): Observable { return from(_getMetadata(ref)); } From 38fd4a0d3f4d8b054ce6843248736a229f19f833 Mon Sep 17 00:00:00 2001 From: KingDarBoja <30560560+KingDarBoja@users.noreply.github.com> Date: Fri, 11 Sep 2026 14:04:37 -0500 Subject: [PATCH 3/5] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20types:=20enhance=20?= =?UTF-8?q?type=20definitions=20for=20collectionCount=20and=20CountSnapsho?= =?UTF-8?q?t=20functions.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- firestore/collection/index.ts | 8 ++++++-- firestore/lite/interfaces.ts | 18 ++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/firestore/collection/index.ts b/firestore/collection/index.ts index 1a2ae88..810be1e 100644 --- a/firestore/collection/index.ts +++ b/firestore/collection/index.ts @@ -298,10 +298,14 @@ export function collectionData( ); } -export function collectionCountSnap(query: Query): Observable { +export function collectionCountSnap( + query: Query, +): Observable> { return from(getCountFromServer(query)); } -export function collectionCount(query: Query): Observable { +export function collectionCount( + query: Query, +): Observable { return collectionCountSnap(query).pipe(map((snap) => snap.data().count)); } diff --git a/firestore/lite/interfaces.ts b/firestore/lite/interfaces.ts index a9ba75c..a4d6332 100644 --- a/firestore/lite/interfaces.ts +++ b/firestore/lite/interfaces.ts @@ -2,10 +2,20 @@ import type * as lite from 'firebase/firestore/lite'; export type DocumentReference = lite.DocumentReference; export type DocumentData = lite.DocumentData; -export type Query = lite.Query; +export type Query< + AppModelType, + DbModelType extends DocumentData = DocumentData, +> = lite.Query; export type DocumentSnapshot = lite.DocumentSnapshot; export type QuerySnapshot = lite.QuerySnapshot; export type QueryDocumentSnapshot = lite.QueryDocumentSnapshot; -export type CountSnapshot = lite.AggregateQuerySnapshot<{ - count: lite.AggregateField; -}, any, DocumentData>; +export type CountSnapshot< + AppModelType = DocumentData, + DbModelType extends DocumentData = DocumentData, +> = lite.AggregateQuerySnapshot< + { + count: lite.AggregateField; + }, + AppModelType, + DbModelType +>; From d7bdfc8d565620f304dd5a2bbb041ed89e6b06a3 Mon Sep 17 00:00:00 2001 From: KingDarBoja <30560560+KingDarBoja@users.noreply.github.com> Date: Fri, 11 Sep 2026 15:10:33 -0500 Subject: [PATCH 4/5] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20types:=20preserve?= =?UTF-8?q?=20converter=20instances=20in=20docData=20when=20idField=20is?= =?UTF-8?q?=20set?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- firestore/document/index.ts | 8 ++++---- test/firestore.test.ts | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/firestore/document/index.ts b/firestore/document/index.ts index 0025501..86ffc16 100644 --- a/firestore/document/index.ts +++ b/firestore/document/index.ts @@ -54,8 +54,8 @@ export function snapToData( return data; } - return { - ...data, - [options.idField]: snapshot.id, - }; + // Preserve converter instances and custom prototypes by mutating the original object + // instead of creating a new one with spread syntax. + (data as Record)[options.idField as string] = snapshot.id; + return data; } diff --git a/test/firestore.test.ts b/test/firestore.test.ts index 0274c3a..b80df39 100644 --- a/test/firestore.test.ts +++ b/test/firestore.test.ts @@ -416,6 +416,29 @@ describe('RxFire Firestore', () => { }); }); + it('docData should preserve converter instances when idField is set', (done: jest.DoneCallback) => { + class Folk { + constructor(public name: string) {} + static fromFirestore(snap: QueryDocumentSnapshot) { + return new Folk(snap.data().name); + } + static toFirestore(model: Folk) { + return model; + } + } + + seedTest(firestore).then(({davidDoc}) => { + const unwrapped = docData(davidDoc.withConverter(Folk), {idField: 'UID'}); + + unwrapped.pipe(take(1)).subscribe((val) => { + expect(val).toBeInstanceOf(Folk); + expect((val as Folk).name).toBe('David'); + expect((val as Folk & {UID: string}).UID).toBe('david'); + done(); + }); + }); + }); + /** * TODO(jamesdaniels) * Having trouble gettings these test green with the emulators From 8262258e8044c9f70ff44899f03b3ffeb3df6866 Mon Sep 17 00:00:00 2001 From: KingDarBoja <30560560+KingDarBoja@users.noreply.github.com> Date: Fri, 11 Sep 2026 15:11:02 -0500 Subject: [PATCH 5/5] =?UTF-8?q?=F0=9F=8F=B7=EF=B8=8F=20types:=20enhance=20?= =?UTF-8?q?type=20definitions=20for=20collection=20count=20functions=20at?= =?UTF-8?q?=20firestore=20lite.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- firestore/lite/collection/index.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/firestore/lite/collection/index.ts b/firestore/lite/collection/index.ts index 2bab09c..9dcd1f3 100644 --- a/firestore/lite/collection/index.ts +++ b/firestore/lite/collection/index.ts @@ -48,10 +48,15 @@ export function collectionData( ); } -export function collectionCountSnap(query: Query): Observable { - return from(getCount(query)); +export function collectionCountSnap< + AppModelType = DocumentData, + DbModelType extends DocumentData = DocumentData, +>(query: Query): Observable> { + return from(getCount(query) as Promise>); } -export function collectionCount(query: Query): Observable { +export function collectionCount( + query: Query, +): Observable { return collectionCountSnap(query).pipe(map((snap) => snap.data().count)); }