Skip to content

Commit 7b28316

Browse files
committed
feat: improved types to properly infer and include IDField and RefField options
1 parent 9eab1ce commit 7b28316

File tree

5 files changed

+77
-40
lines changed

5 files changed

+77
-40
lines changed

docs/firestore.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,4 @@ The `transform` function is passed a single row of a data, so will be called onc
290290

291291
The `transform` function will not receive the `id` or `ref` values referenced in the properties named in the `idField` or `refField` options, nor it is expected to produce them. Either or both, if specified, will be merged afterwards.
292292

293-
If the `transform` function is defined within your React component, it is recomended that you memoize the function to prevent unnecessry renders.
293+
If the `transform` function is defined within your React component, it is recommended that you memoize the function to prevent unnecessary renders.

src/firestore/helpers/index.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
11
import type { FirebaseFirestoreTypes } from '@react-native-firebase/firestore';
2+
import type { Data } from '../types';
23

3-
export const snapshotToData = <T = FirebaseFirestoreTypes.DocumentData>(
4+
export const snapshotToData = <
5+
T = FirebaseFirestoreTypes.DocumentData,
6+
IDField extends string | undefined = undefined,
7+
RefField extends string | undefined = undefined
8+
>(
49
snapshot: FirebaseFirestoreTypes.DocumentSnapshot<T>,
5-
idField?: string,
6-
refField?: string,
10+
idField?: IDField,
11+
refField?: RefField,
712
transform?: (val: any) => T
8-
) => {
13+
): Data<T, IDField, RefField> | undefined => {
914
if (!snapshot.exists) {
1015
return undefined;
1116
}
1217

13-
let data = snapshot.data() as FirebaseFirestoreTypes.DocumentData;
18+
let data = snapshot.data();
19+
// this case should never happen as, we did a earlier exists check
20+
// so this line here is more to satisfy TS
21+
if (data == null) return undefined;
22+
1423
if (transform) {
1524
data = transform(data);
1625
}
17-
if (idField) {
26+
if (typeof idField === 'string') {
27+
// @ts-expect-error We add a new field to a predefined object
1828
data[idField] = snapshot.id;
1929
}
20-
if (refField) {
30+
if (typeof refField === 'string') {
31+
// @ts-expect-error We add a new field to a predefined object
2132
data[refField] = snapshot.ref;
2233
}
2334

35+
// @ts-expect-error TODO: is there any way we can convince it, that it conforms the Data type?
2436
return data;
2537
};

src/firestore/types.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,50 @@
11
import type { LoadingHook } from '../util';
22
import type { FirebaseFirestoreTypes } from '@react-native-firebase/firestore';
33

4-
export type IDOptions<T> = {
5-
idField?: string;
6-
refField?: string;
4+
export type IDOptions<
5+
T,
6+
IDField extends string | undefined = undefined,
7+
RefField extends string | undefined = undefined
8+
> = {
9+
idField?: IDField;
10+
refField?: RefField;
711
transform?: (val: any) => T;
812
};
913
export type Options = {
1014
snapshotListenOptions?: FirebaseFirestoreTypes.SnapshotListenOptions;
1115
};
12-
export type DataOptions<T> = Options & IDOptions<T>;
16+
export type DataOptions<
17+
T,
18+
IDField extends string | undefined = undefined,
19+
RefField extends string | undefined = undefined
20+
> = Options & IDOptions<T, IDField, RefField>;
1321
export type OnceOptions = {
1422
getOptions?: GetOptions;
1523
};
1624
export type GetOptions = {
1725
source?: 'default' | 'server' | 'cache';
1826
};
19-
export type OnceDataOptions<T> = OnceOptions & IDOptions<T>;
27+
export type OnceDataOptions<
28+
T,
29+
IDField extends string | undefined = undefined,
30+
RefField extends string | undefined = undefined
31+
> = OnceOptions & IDOptions<T, IDField, RefField>;
2032
export type Data<
2133
T = FirebaseFirestoreTypes.DocumentData,
22-
IDField extends string = '',
23-
RefField extends string = ''
34+
IDField extends string | undefined = undefined,
35+
RefField extends string | undefined = undefined
2436
> = T &
25-
Record<IDField, string> &
26-
Record<RefField, FirebaseFirestoreTypes.DocumentReference<T>>;
37+
(IDField extends string ? Record<IDField, string> : {}) &
38+
(RefField extends string
39+
? Record<RefField, FirebaseFirestoreTypes.DocumentReference<T>>
40+
: {});
2741

2842
export type CollectionHook<T = FirebaseFirestoreTypes.DocumentData> =
2943
LoadingHook<FirebaseFirestoreTypes.QuerySnapshot<T>, Error>;
3044
export type CollectionDataHook<
3145
T = FirebaseFirestoreTypes.DocumentData,
32-
IDField extends string = '',
33-
RefField extends string = ''
46+
IDField extends string | undefined = undefined,
47+
RefField extends string | undefined = undefined
3448
> = LoadingHook<Data<T, IDField, RefField>[], Error>;
3549

3650
export type DocumentHook<T = FirebaseFirestoreTypes.DocumentData> = LoadingHook<
@@ -39,6 +53,6 @@ export type DocumentHook<T = FirebaseFirestoreTypes.DocumentData> = LoadingHook<
3953
>;
4054
export type DocumentDataHook<
4155
T = FirebaseFirestoreTypes.DocumentData,
42-
IDField extends string = '',
43-
RefField extends string = ''
56+
IDField extends string | undefined = undefined,
57+
RefField extends string | undefined = undefined
4458
> = LoadingHook<Data<T, IDField, RefField>, Error>;

src/firestore/useCollection.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,19 @@ export const useCollectionOnce = <T = FirebaseFirestoreTypes.DocumentData>(
2828

2929
export const useCollectionData = <
3030
T = FirebaseFirestoreTypes.DocumentData,
31-
IDField extends string = '',
32-
RefField extends string = ''
31+
IDField extends string | undefined = undefined,
32+
RefField extends string | undefined = undefined
3333
>(
3434
query?: FirebaseFirestoreTypes.Query<T> | null,
35-
options?: DataOptions<T>
35+
options?: DataOptions<T, IDField, RefField>
3636
): CollectionDataHook<T, IDField, RefField> => {
3737
return useCollectionDataInternal<T, IDField, RefField>(true, query, options);
3838
};
3939

4040
export const useCollectionDataOnce = <
4141
T = FirebaseFirestoreTypes.DocumentData,
42-
IDField extends string = '',
43-
RefField extends string = ''
42+
IDField extends string | undefined = undefined,
43+
RefField extends string | undefined = undefined
4444
>(
4545
query?: FirebaseFirestoreTypes.Query<T> | null,
4646
options?: OnceDataOptions<T>
@@ -101,12 +101,13 @@ const useCollectionInternal = <T = FirebaseFirestoreTypes.DocumentData>(
101101

102102
const useCollectionDataInternal = <
103103
T = FirebaseFirestoreTypes.DocumentData,
104-
IDField extends string = '',
105-
RefField extends string = ''
104+
IDField extends string | undefined = undefined,
105+
RefField extends string | undefined = undefined
106106
>(
107107
listen: boolean,
108108
query?: FirebaseFirestoreTypes.Query<T> | null,
109-
options?: DataOptions<T> & OnceDataOptions<T>
109+
options?: DataOptions<T, IDField, RefField> &
110+
OnceDataOptions<T, IDField, RefField>
110111
): CollectionDataHook<T, IDField, RefField> => {
111112
const idField = options ? options.idField : undefined;
112113
const refField = options ? options.refField : undefined;
@@ -120,7 +121,12 @@ const useCollectionDataInternal = <
120121
() =>
121122
(snapshots
122123
? snapshots.docs.map((doc) =>
123-
snapshotToData<T>(doc, idField, refField, transform)
124+
snapshotToData<T, IDField, RefField>(
125+
doc,
126+
idField,
127+
refField,
128+
transform
129+
)
124130
)
125131
: undefined) as Data<T, IDField, RefField>[],
126132
[snapshots, idField, refField, transform]

src/firestore/useDocument.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,22 @@ export const useDocumentOnce = <T = FirebaseFirestoreTypes.DocumentData>(
2828

2929
export const useDocumentData = <
3030
T = FirebaseFirestoreTypes.DocumentData,
31-
IDField extends string = '',
32-
RefField extends string = ''
31+
IDField extends string | undefined = undefined,
32+
RefField extends string | undefined = undefined
3333
>(
3434
docRef?: FirebaseFirestoreTypes.DocumentReference<T> | null,
35-
options?: DataOptions<T>
35+
options?: DataOptions<T, IDField, RefField>
3636
): DocumentDataHook<T, IDField, RefField> => {
3737
return useDocumentDataInternal<T, IDField, RefField>(true, docRef, options);
3838
};
3939

4040
export const useDocumentDataOnce = <
4141
T = FirebaseFirestoreTypes.DocumentData,
42-
IDField extends string = '',
43-
RefField extends string = ''
42+
IDField extends string | undefined = undefined,
43+
RefField extends string | undefined = undefined
4444
>(
4545
docRef?: FirebaseFirestoreTypes.DocumentReference<T> | null,
46-
options?: OnceDataOptions<T>
46+
options?: OnceDataOptions<T, IDField, RefField>
4747
): DocumentDataHook<T, IDField, RefField> => {
4848
return useDocumentDataInternal<T, IDField, RefField>(false, docRef, options);
4949
};
@@ -104,12 +104,12 @@ const useDocumentInternal = <T = FirebaseFirestoreTypes.DocumentData>(
104104

105105
const useDocumentDataInternal = <
106106
T = FirebaseFirestoreTypes.DocumentData,
107-
IDField extends string = '',
108-
RefField extends string = ''
107+
IDField extends string | undefined = undefined,
108+
RefField extends string | undefined = undefined
109109
>(
110110
listen: boolean,
111111
docRef?: FirebaseFirestoreTypes.DocumentReference<T> | null,
112-
options?: DataOptions<T>
112+
options?: DataOptions<T, IDField, RefField>
113113
): DocumentDataHook<T, IDField, RefField> => {
114114
const idField = options ? options.idField : undefined;
115115
const refField = options ? options.refField : undefined;
@@ -122,7 +122,12 @@ const useDocumentDataInternal = <
122122
const value = useMemo(
123123
() =>
124124
(snapshot
125-
? snapshotToData<T>(snapshot, idField, refField, transform)
125+
? snapshotToData<T, IDField, RefField>(
126+
snapshot,
127+
idField,
128+
refField,
129+
transform
130+
)
126131
: undefined) as Data<T, IDField, RefField>,
127132
[snapshot, idField, refField, transform]
128133
);

0 commit comments

Comments
 (0)