Skip to content

Commit 796b7c1

Browse files
fix(firestore): doc and collection methods generic (#2649)
Co-authored-by: KingDarBoja <[email protected]>
1 parent 6934310 commit 796b7c1

File tree

9 files changed

+49
-47
lines changed

9 files changed

+49
-47
lines changed

src/firestore/collection-group/collection-group.spec.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { AngularFireModule, FirebaseApp } from '@angular/fire';
22
import { AngularFirestore, AngularFirestoreCollectionGroup, AngularFirestoreModule, SETTINGS } from '../public_api';
3-
import { Query, QueryGroupFn } from '../interfaces';
3+
import { QueryGroupFn, Query } from '../interfaces';
44
import { BehaviorSubject } from 'rxjs';
55
import { skip, switchMap, take } from 'rxjs/operators';
66
import { TestBed } from '@angular/core/testing';
@@ -19,11 +19,11 @@ import {
1919
Stock
2020
} from '../utils.spec';
2121

22-
async function collectionHarness(afs: AngularFirestore, items: number, queryGroupFn?: QueryGroupFn) {
22+
async function collectionHarness(afs: AngularFirestore, items: number, queryGroupFn?: QueryGroupFn<Stock>) {
2323
const randomCollectionName = randomName(afs.firestore);
2424
const ref = afs.firestore.collection(`${randomCollectionName}`);
25-
const firestore: any = afs.firestore;
26-
const collectionGroup: Query = firestore.collectionGroup(randomCollectionName);
25+
const firestore = afs.firestore;
26+
const collectionGroup = firestore.collectionGroup(randomCollectionName) as Query<Stock>;
2727
const queryFn = queryGroupFn || (ref => ref);
2828
const stocks = new AngularFirestoreCollectionGroup<Stock>(queryFn(collectionGroup), afs);
2929
const names = await createRandomStocks(afs.firestore, ref, items);

src/firestore/collection-group/collection-group.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ import { AngularFirestore } from '../firestore';
2626
* // Subscribe to changes as snapshots. This provides you data updates as well as delta updates.
2727
* fakeStock.valueChanges().subscribe(value => console.log(value));
2828
*/
29-
export class AngularFirestoreCollectionGroup<T= DocumentData> {
29+
export class AngularFirestoreCollectionGroup<T = DocumentData> {
3030
/**
3131
* The constructor takes in a CollectionGroupQuery to provide wrapper methods
3232
* for data operations and data streaming.
3333
*/
3434
constructor(
35-
private readonly query: Query,
35+
private readonly query: Query<T>,
3636
private readonly afs: AngularFirestore) { }
3737

3838
/**

src/firestore/collection/collection.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { AngularFireModule, FirebaseApp } from '@angular/fire';
22
import { AngularFirestore, SETTINGS } from '../firestore';
33
import { AngularFirestoreModule } from '../firestore.module';
44
import { AngularFirestoreCollection } from './collection';
5-
import { QueryFn } from '../interfaces';
5+
import { QueryFn, CollectionReference } from '../interfaces';
66
import { BehaviorSubject } from 'rxjs';
77
import { skip, switchMap, take } from 'rxjs/operators';
88
import 'firebase/firestore';
@@ -22,9 +22,9 @@ import {
2222
Stock
2323
} from '../utils.spec';
2424

25-
async function collectionHarness(afs: AngularFirestore, items: number, queryFn?: QueryFn) {
25+
async function collectionHarness(afs: AngularFirestore, items: number, queryFn?: QueryFn<Stock>) {
2626
const randomCollectionName = randomName(afs.firestore);
27-
const ref = afs.firestore.collection(`${randomCollectionName}`);
27+
const ref = afs.firestore.collection(`${randomCollectionName}`) as CollectionReference<Stock>;
2828
if (!queryFn) {
2929
queryFn = (ref) => ref;
3030
}

src/firestore/collection/collection.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ export function validateEventsArray(events?: DocumentChangeType[]) {
3838
* // Subscribe to changes as snapshots. This provides you data updates as well as delta updates.
3939
* fakeStock.valueChanges().subscribe(value => console.log(value));
4040
*/
41-
export class AngularFirestoreCollection<T= DocumentData> {
41+
export class AngularFirestoreCollection<T = DocumentData> {
4242
/**
4343
* The constructor takes in a CollectionReference and Query to provide wrapper methods
4444
* for data operations and data streaming.
@@ -49,8 +49,8 @@ export class AngularFirestoreCollection<T= DocumentData> {
4949
* on this implication.
5050
*/
5151
constructor(
52-
public readonly ref: CollectionReference,
53-
private readonly query: Query,
52+
public readonly ref: CollectionReference<T>,
53+
private readonly query: Query<T>,
5454
private readonly afs: AngularFirestore) { }
5555

5656
/**
@@ -134,14 +134,14 @@ export class AngularFirestoreCollection<T= DocumentData> {
134134
* when you update data it is not updating data to the window of your query unless
135135
* the data fits the criteria of the query.
136136
*/
137-
add(data: T): Promise<DocumentReference> {
137+
add(data: T): Promise<DocumentReference<T>> {
138138
return this.ref.add(data);
139139
}
140140

141141
/**
142142
* Create a reference to a single document in a collection.
143143
*/
144-
doc<T2 = T>(path?: string): AngularFirestoreDocument<T2> {
145-
return new AngularFirestoreDocument<T2>(this.ref.doc(path), this.afs);
144+
doc(path?: string): AngularFirestoreDocument<T> {
145+
return new AngularFirestoreDocument<T>(this.ref.doc(path), this.afs);
146146
}
147147
}

src/firestore/document/document.spec.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ import { AngularFirestore, SETTINGS } from '../firestore';
33
import { AngularFirestoreModule } from '../firestore.module';
44
import { Subscription } from 'rxjs';
55
import { AngularFirestoreDocument } from './document';
6+
import { DocumentReference } from '../interfaces';
67
import { take } from 'rxjs/operators';
78

89
import { TestBed } from '@angular/core/testing';
910
import { COMMON_CONFIG } from '../../test-config';
1011

1112
import { FAKE_STOCK_DATA, rando, randomName, Stock } from '../utils.spec';
13+
import firebase from 'firebase/app';
1214
import 'firebase/firestore';
1315

1416
describe('AngularFirestoreDocument', () => {
@@ -38,8 +40,8 @@ describe('AngularFirestoreDocument', () => {
3840

3941
it('should get unwrapped snapshot', async (done: any) => {
4042
const randomCollectionName = afs.firestore.collection('a').doc().id;
41-
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`);
42-
const stock = new AngularFirestoreDocument<Stock>(ref, afs);
43+
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`) as firebase.firestore.DocumentReference<Stock>;
44+
const stock = new AngularFirestoreDocument(ref, afs);
4345
await stock.set(FAKE_STOCK_DATA);
4446
const obs$ = stock.valueChanges();
4547
obs$.pipe(take(1)).subscribe(async data => {
@@ -69,7 +71,7 @@ describe('AngularFirestoreDocument', () => {
6971

7072
it('should get action updates', async (done: any) => {
7173
const randomCollectionName = randomName(afs.firestore);
72-
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`);
74+
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`) as DocumentReference<Stock>;
7375
const stock = new AngularFirestoreDocument<Stock>(ref, afs);
7476
await stock.set(FAKE_STOCK_DATA);
7577
const sub = stock
@@ -85,7 +87,7 @@ describe('AngularFirestoreDocument', () => {
8587

8688
it('should get unwrapped snapshot', async (done: any) => {
8789
const randomCollectionName = afs.firestore.collection('a').doc().id;
88-
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`);
90+
const ref = afs.firestore.doc(`${randomCollectionName}/FAKE`) as DocumentReference<Stock>;
8991
const stock = new AngularFirestoreDocument<Stock>(ref, afs);
9092
await stock.set(FAKE_STOCK_DATA);
9193
const obs$ = stock.valueChanges();

src/firestore/document/document.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ import firebase from 'firebase/app';
3131
export class AngularFirestoreDocument<T = DocumentData> {
3232

3333
/**
34-
* The contstuctor takes in a DocumentReference to provide wrapper methods
34+
* The constructor takes in a DocumentReference to provide wrapper methods
3535
* for data operations, data streaming, and Symbol.observable.
3636
*/
37-
constructor(public ref: DocumentReference, private afs: AngularFirestore) { }
37+
constructor(public ref: DocumentReference<T>, private afs: AngularFirestore) { }
3838

3939
/**
4040
* Create or overwrite a single document.
@@ -62,9 +62,9 @@ export class AngularFirestoreDocument<T = DocumentData> {
6262
* function.
6363
*/
6464
collection<R = DocumentData>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<R> {
65-
const collectionRef = this.ref.collection(path);
65+
const collectionRef = this.ref.collection(path) as firebase.firestore.CollectionReference<R>;
6666
const { ref, query } = associateQuery(collectionRef, queryFn);
67-
return new AngularFirestoreCollection<R>(ref, query, this.afs);
67+
return new AngularFirestoreCollection(ref, query, this.afs);
6868
}
6969

7070
/**

src/firestore/firestore.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const SETTINGS = new InjectionToken<Settings>('angularfire2.firestore.set
4646
* return ref.where('age', '<', 200);
4747
* });
4848
*/
49-
export function associateQuery(collectionRef: CollectionReference, queryFn = ref => ref): AssociatedReference {
49+
export function associateQuery<T>(collectionRef: CollectionReference<T>, queryFn = ref => ref): AssociatedReference<T> {
5050
const query = queryFn(collectionRef);
5151
const ref = collectionRef;
5252
return { query, ref };
@@ -173,14 +173,14 @@ export class AngularFirestore {
173173
collection<T>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<T>;
174174
// tslint:disable-next-line:unified-signatures
175175
collection<T>(ref: CollectionReference, queryFn?: QueryFn): AngularFirestoreCollection<T>;
176-
collection<T>(pathOrRef: string | CollectionReference, queryFn?: QueryFn): AngularFirestoreCollection<T> {
177-
let collectionRef: CollectionReference;
176+
collection<T>(pathOrRef: string | CollectionReference<T>, queryFn?: QueryFn): AngularFirestoreCollection<T> {
177+
let collectionRef: CollectionReference<T>;
178178
if (typeof pathOrRef === 'string') {
179-
collectionRef = this.firestore.collection(pathOrRef);
179+
collectionRef = this.firestore.collection(pathOrRef) as firebase.firestore.CollectionReference<T>;
180180
} else {
181181
collectionRef = pathOrRef;
182182
}
183-
const { ref, query } = associateQuery(collectionRef, queryFn);
183+
const { ref, query } = associateQuery<T>(collectionRef, queryFn);
184184
const refInZone = this.schedulers.ngZone.run(() => ref);
185185
return new AngularFirestoreCollection<T>(refInZone, query, this);
186186
}
@@ -190,9 +190,9 @@ export class AngularFirestore {
190190
* and an optional query function to narrow the result
191191
* set.
192192
*/
193-
collectionGroup<T>(collectionId: string, queryGroupFn?: QueryGroupFn): AngularFirestoreCollectionGroup<T> {
193+
collectionGroup<T>(collectionId: string, queryGroupFn?: QueryGroupFn<T>): AngularFirestoreCollectionGroup<T> {
194194
const queryFn = queryGroupFn || (ref => ref);
195-
const collectionGroup: Query = this.firestore.collectionGroup(collectionId);
195+
const collectionGroup: Query<T> = this.firestore.collectionGroup(collectionId) as firebase.firestore.Query<T>;
196196
return new AngularFirestoreCollectionGroup<T>(queryFn(collectionGroup), this);
197197
}
198198

@@ -205,10 +205,10 @@ export class AngularFirestore {
205205
doc<T>(path: string): AngularFirestoreDocument<T>;
206206
// tslint:disable-next-line:unified-signatures
207207
doc<T>(ref: DocumentReference): AngularFirestoreDocument<T>;
208-
doc<T>(pathOrRef: string | DocumentReference): AngularFirestoreDocument<T> {
209-
let ref: DocumentReference;
208+
doc<T>(pathOrRef: string | DocumentReference<T>): AngularFirestoreDocument<T> {
209+
let ref: DocumentReference<T>;
210210
if (typeof pathOrRef === 'string') {
211-
ref = this.firestore.doc(pathOrRef);
211+
ref = this.firestore.doc(pathOrRef) as firebase.firestore.DocumentReference<T>;
212212
} else {
213213
ref = pathOrRef;
214214
}

src/firestore/interfaces.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ import { Subscriber } from 'rxjs';
22
import firebase from 'firebase/app';
33

44
export type Settings = firebase.firestore.Settings;
5-
export type CollectionReference = firebase.firestore.CollectionReference;
6-
export type DocumentReference = firebase.firestore.DocumentReference;
5+
export type CollectionReference<T = DocumentData> = firebase.firestore.CollectionReference<T>;
6+
export type DocumentReference<T = DocumentData> = firebase.firestore.DocumentReference<T>;
77
export type PersistenceSettings = firebase.firestore.PersistenceSettings;
88
export type DocumentChangeType = firebase.firestore.DocumentChangeType;
99
export type SnapshotOptions = firebase.firestore.SnapshotOptions;
1010
export type FieldPath = firebase.firestore.FieldPath;
11-
export type Query = firebase.firestore.Query;
11+
export type Query<T = DocumentData> = firebase.firestore.Query<T>;
1212

1313
export type SetOptions = firebase.firestore.SetOptions;
1414
export type DocumentData = firebase.firestore.DocumentData;
@@ -54,9 +54,9 @@ export interface Reference<T> {
5454

5555
// A convience type for making a query.
5656
// Example: const query = (ref) => ref.where('name', == 'david');
57-
export type QueryFn = (ref: CollectionReference) => Query;
57+
export type QueryFn<T = DocumentData> = (ref: CollectionReference<T>) => Query<T>;
5858

59-
export type QueryGroupFn = (query: Query) => Query;
59+
export type QueryGroupFn<T = DocumentData> = (query: Query<T>) => Query<T>;
6060

6161
/**
6262
* A structure that provides an association between a reference
@@ -80,7 +80,7 @@ export type QueryGroupFn = (query: Query) => Query;
8080
* publisher: 'SportsPublisher'
8181
* });
8282
*/
83-
export interface AssociatedReference {
84-
ref: CollectionReference;
85-
query: Query;
83+
export interface AssociatedReference<T = DocumentData> {
84+
ref: CollectionReference<T>;
85+
query: Query<T>;
8686
}

src/firestore/observable/fromRef.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { map } from 'rxjs/operators';
44

55
function _fromRef<T, R>(ref: Reference<T>, scheduler: SchedulerLike = asyncScheduler): Observable<R> {
66
return new Observable(subscriber => {
7-
let unsubscribe;
7+
let unsubscribe: () => void;
88
if (scheduler != null) {
99
scheduler.schedule(() => {
1010
unsubscribe = ref.onSnapshot(subscriber);
@@ -21,17 +21,17 @@ function _fromRef<T, R>(ref: Reference<T>, scheduler: SchedulerLike = asyncSched
2121
});
2222
}
2323

24-
export function fromRef<R>(ref: DocumentReference | Query, scheduler?: SchedulerLike) {
24+
export function fromRef<R, T>(ref: DocumentReference<T> | Query<T>, scheduler?: SchedulerLike) {
2525
return _fromRef<typeof ref, R>(ref, scheduler);
2626
}
2727

28-
export function fromDocRef<T>(ref: DocumentReference, scheduler?: SchedulerLike): Observable<Action<DocumentSnapshot<T>>> {
29-
return fromRef<DocumentSnapshot<T>>(ref, scheduler)
28+
export function fromDocRef<T>(ref: DocumentReference<T>, scheduler?: SchedulerLike): Observable<Action<DocumentSnapshot<T>>> {
29+
return fromRef<DocumentSnapshot<T>, T>(ref, scheduler)
3030
.pipe(
3131
map(payload => ({ payload, type: 'value' }))
3232
);
3333
}
3434

35-
export function fromCollectionRef<T>(ref: Query, scheduler?: SchedulerLike): Observable<Action<QuerySnapshot<T>>> {
36-
return fromRef<QuerySnapshot<T>>(ref, scheduler).pipe(map(payload => ({ payload, type: 'query' })));
35+
export function fromCollectionRef<T>(ref: Query<T>, scheduler?: SchedulerLike): Observable<Action<QuerySnapshot<T>>> {
36+
return fromRef<QuerySnapshot<T>, T>(ref, scheduler).pipe(map(payload => ({ payload, type: 'query' })));
3737
}

0 commit comments

Comments
 (0)