Skip to content

Commit 211876d

Browse files
authored
Merge pull request codediodeio#108 from trickypr/generic-components
Add generics to `Collection` and `Doc`
2 parents 9629e94 + b10de03 commit 211876d

File tree

10 files changed

+77
-82
lines changed

10 files changed

+77
-82
lines changed

dist/components/Collection.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<script>import { collectionStore } from "../stores/firestore.js";
1+
<script generics="Data extends DocumentData">import { collectionStore } from "../stores/firestore.js";
22
import { getFirebaseContext } from "../stores/sdk.js";
33
export let ref;
44
export let startWith = void 0;
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
import { SvelteComponent } from "svelte";
2-
import type { CollectionReference, Firestore, Query } from 'firebase/firestore';
3-
declare const __propDef: {
4-
props: {
5-
ref: string | CollectionReference | Query;
6-
startWith?: any;
2+
import type { CollectionReference, DocumentData, Firestore, Query } from "firebase/firestore";
3+
declare class __sveltets_Render<Data extends DocumentData> {
4+
props(): {
5+
ref: string | CollectionReference<Data> | Query<Data>;
6+
startWith?: Data[] | undefined;
77
};
8-
events: {
8+
events(): {} & {
99
[evt: string]: CustomEvent<any>;
1010
};
11-
slots: {
11+
slots(): {
1212
default: {
13-
data: any[];
14-
ref: CollectionReference | Query | null;
13+
data: Data[];
14+
ref: CollectionReference<Data[]> | Query<Data[]> | null;
1515
count: number;
1616
firestore?: Firestore | undefined;
1717
};
1818
loading: {};
1919
};
20-
};
21-
export type CollectionProps = typeof __propDef.props;
22-
export type CollectionEvents = typeof __propDef.events;
23-
export type CollectionSlots = typeof __propDef.slots;
24-
export default class Collection extends SvelteComponent<CollectionProps, CollectionEvents, CollectionSlots> {
20+
}
21+
export type CollectionProps<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['props']>;
22+
export type CollectionEvents<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['events']>;
23+
export type CollectionSlots<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['slots']>;
24+
export default class Collection<Data extends DocumentData> extends SvelteComponent<CollectionProps<Data>, CollectionEvents<Data>, CollectionSlots<Data>> {
2525
}
2626
export {};

dist/components/Doc.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
<script>import { docStore } from "../stores/firestore.js";
1+
<script generics="Data extends DocumentData">import { docStore } from "../stores/firestore.js";
22
import { getFirebaseContext } from "../stores/sdk.js";
33
export let ref;
44
export let startWith = void 0;
55
const { firestore } = getFirebaseContext();
66
let store = docStore(firestore, ref, startWith);
77
</script>
88

9-
{#if $store !== undefined}
9+
{#if $store !== undefined && $store !== null}
1010
<slot data={$store} ref={store.ref} {firestore} />
1111
{:else}
1212
<slot name="loading" />

dist/components/Doc.svelte.d.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
import { SvelteComponent } from "svelte";
2-
import type { DocumentReference, Firestore } from 'firebase/firestore';
3-
declare const __propDef: {
4-
props: {
5-
ref: string | DocumentReference;
6-
startWith?: any;
2+
import type { DocumentData, DocumentReference, Firestore } from "firebase/firestore";
3+
declare class __sveltets_Render<Data extends DocumentData> {
4+
props(): {
5+
ref: string | DocumentReference<Data>;
6+
startWith?: Data | undefined;
77
};
8-
events: {
8+
events(): {} & {
99
[evt: string]: CustomEvent<any>;
1010
};
11-
slots: {
11+
slots(): {
1212
default: {
13-
data: any;
14-
ref: DocumentReference | null;
13+
data: Data;
14+
ref: DocumentReference<Data> | null;
1515
firestore?: Firestore | undefined;
1616
};
1717
loading: {};
1818
};
19-
};
20-
export type DocProps = typeof __propDef.props;
21-
export type DocEvents = typeof __propDef.events;
22-
export type DocSlots = typeof __propDef.slots;
23-
export default class Doc extends SvelteComponent<DocProps, DocEvents, DocSlots> {
19+
}
20+
export type DocProps<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['props']>;
21+
export type DocEvents<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['events']>;
22+
export type DocSlots<Data extends DocumentData> = ReturnType<__sveltets_Render<Data>['slots']>;
23+
export default class Doc<Data extends DocumentData> extends SvelteComponent<DocProps<Data>, DocEvents<Data>, DocSlots<Data>> {
2424
}
2525
export {};

dist/stores/firestore.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ interface DocStore<T> {
1313
export declare function docStore<T = any>(firestore: Firestore, ref: string | DocumentReference<T>, startWith?: T): DocStore<T>;
1414
interface CollectionStore<T> {
1515
subscribe: (cb: (value: T | []) => void) => void | (() => void);
16-
ref: CollectionReference | Query | null;
16+
ref: CollectionReference<T> | Query<T> | null;
1717
}
1818
/**
1919
* @param {Firestore} firestore firebase firestore instance
2020
* @param {string|Query|CollectionReference} ref collection path, reference, or query
2121
* @param {[]} startWith optional default data
2222
* @returns a store with realtime updates on collection data
2323
*/
24-
export declare function collectionStore<T>(firestore: Firestore, ref: string | Query | CollectionReference, startWith?: T[]): CollectionStore<T[]>;
24+
export declare function collectionStore<T>(firestore: Firestore, ref: string | Query<T> | CollectionReference<T>, startWith?: T[]): CollectionStore<T[]>;
2525
export {};

dist/stores/firestore.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ export function docStore(firestore, ref, startWith) {
2727
id: "",
2828
};
2929
}
30-
const docRef = typeof ref === 'string' ? doc(firestore, ref) : ref;
30+
const docRef = typeof ref === "string"
31+
? doc(firestore, ref)
32+
: ref;
3133
const { subscribe } = writable(startWith, (set) => {
3234
unsubscribe = onSnapshot(docRef, (snapshot) => {
3335
set(snapshot.data() ?? null);

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/components/Collection.svelte

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,29 @@
1-
<script lang="ts">
1+
<script lang="ts" generics="Data extends DocumentData">
22
import type {
33
CollectionReference,
4+
DocumentData,
45
Firestore,
56
Query,
6-
} from 'firebase/firestore';
7-
import { collectionStore } from '../stores/firestore.js';
8-
import { getFirebaseContext } from '../stores/sdk.js';
7+
} from "firebase/firestore";
8+
import { collectionStore } from "../stores/firestore.js";
9+
import { getFirebaseContext } from "../stores/sdk.js";
910
10-
// TODO figure out how to make generics work
11-
// current setup will not work without mandatory startWith value
12-
// type T = $$Generic;
13-
14-
// interface $$Slots {
15-
// default: { data: T[], ref: CollectionReference | Query, count: number }
16-
// }
17-
18-
export let ref: string | CollectionReference | Query;
19-
export let startWith: any = undefined;
11+
export let ref: string | CollectionReference<Data> | Query<Data>;
12+
export let startWith: Data[] | undefined = undefined;
2013
2114
const { firestore } = getFirebaseContext();
2215
23-
let store = collectionStore(firestore!, ref, startWith);
16+
let store = collectionStore<Data>(firestore!, ref, startWith);
2417
2518
interface $$Slots {
26-
default: { data: any[]; ref: CollectionReference | Query | null; count: number; firestore?: Firestore },
27-
loading: {},
19+
default: {
20+
data: Data[];
21+
ref: CollectionReference<Data[]> | Query<Data[]> | null;
22+
count: number;
23+
firestore?: Firestore;
24+
};
25+
loading: {};
2826
}
29-
3027
</script>
3128

3229
{#if $store !== undefined}

src/lib/components/Doc.svelte

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,30 @@
1-
<script lang="ts">
2-
import type { DocumentReference, Firestore } from 'firebase/firestore';
3-
import { docStore } from '../stores/firestore.js';
4-
import { getFirebaseContext } from '../stores/sdk.js';
5-
6-
7-
// TODO figure out how to make generics work
8-
// code below will not work without mandatory startWith value
9-
10-
// type T = $$Generic;
11-
12-
// interface $$Slots {
13-
// default: { data: T & { [key: string]: any}, ref: DocumentReference }
14-
// }
15-
16-
export let ref: string | DocumentReference;
17-
export let startWith: any = undefined;
1+
<script lang="ts" generics="Data extends DocumentData">
2+
import type {
3+
DocumentData,
4+
DocumentReference,
5+
Firestore,
6+
} from "firebase/firestore";
7+
import { docStore } from "../stores/firestore.js";
8+
import { getFirebaseContext } from "../stores/sdk.js";
9+
10+
export let ref: string | DocumentReference<Data>;
11+
export let startWith: Data | undefined = undefined;
1812
1913
const { firestore } = getFirebaseContext();
2014
2115
let store = docStore(firestore!, ref, startWith);
2216
2317
interface $$Slots {
24-
default: { data: any; ref: DocumentReference | null; firestore?: Firestore },
25-
loading: {},
18+
default: {
19+
data: Data;
20+
ref: DocumentReference<Data> | null;
21+
firestore?: Firestore;
22+
};
23+
loading: {};
2624
}
27-
2825
</script>
2926

30-
{#if $store !== undefined}
27+
{#if $store !== undefined && $store !== null}
3128
<slot data={$store} ref={store.ref} {firestore} />
3229
{:else}
3330
<slot name="loading" />

src/lib/stores/firestore.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import type {
77
Firestore,
88
} from "firebase/firestore";
99

10-
1110
interface DocStore<T> {
1211
subscribe: (cb: (value: T | null) => void) => void | (() => void);
1312
ref: DocumentReference<T> | null;
@@ -25,7 +24,6 @@ export function docStore<T = any>(
2524
ref: string | DocumentReference<T>,
2625
startWith?: T
2726
): DocStore<T> {
28-
2927
let unsubscribe: () => void;
3028

3129
// Fallback for SSR
@@ -51,7 +49,10 @@ export function docStore<T = any>(
5149
};
5250
}
5351

54-
const docRef = typeof ref === 'string' ? doc(firestore, ref) as DocumentReference<T> : ref;
52+
const docRef =
53+
typeof ref === "string"
54+
? (doc(firestore, ref) as DocumentReference<T>)
55+
: ref;
5556

5657
const { subscribe } = writable<T | null>(startWith, (set) => {
5758
unsubscribe = onSnapshot(docRef, (snapshot) => {
@@ -70,7 +71,7 @@ export function docStore<T = any>(
7071

7172
interface CollectionStore<T> {
7273
subscribe: (cb: (value: T | []) => void) => void | (() => void);
73-
ref: CollectionReference | Query | null;
74+
ref: CollectionReference<T> | Query<T> | null;
7475
}
7576

7677
/**
@@ -81,10 +82,9 @@ interface CollectionStore<T> {
8182
*/
8283
export function collectionStore<T>(
8384
firestore: Firestore,
84-
ref: string | Query | CollectionReference,
85+
ref: string | Query<T> | CollectionReference<T>,
8586
startWith: T[] = []
8687
): CollectionStore<T[]> {
87-
8888
let unsubscribe: () => void;
8989

9090
// Fallback for SSR
@@ -126,4 +126,3 @@ export function collectionStore<T>(
126126
ref: colRef,
127127
};
128128
}
129-

0 commit comments

Comments
 (0)