Skip to content

Commit 3b376f4

Browse files
committed
feat(firestore): allow destructuring from useDocument()
1 parent 1ce4c16 commit 3b376f4

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

src/vuefire/firestore.ts

+47-5
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ export function useDocument<
361361
>(
362362
documentRef: R,
363363
options?: UseDocumentOptions
364-
): Ref<_InferReferenceType<R> | null>
364+
): _RefWithState<_InferReferenceType<R> | null>
365365

366366
/**
367367
* Creates a reactive collection (usually an array) of documents from a collection ref or a query from Firestore.
@@ -374,18 +374,28 @@ export function useDocument<
374374
export function useDocument<T>(
375375
documentRef: DocumentReference,
376376
options?: UseDocumentOptions
377-
): Ref<T | null>
377+
): _RefWithState<T | null>
378378

379379
export function useDocument<T>(
380380
documentRef: DocumentReference<unknown>,
381381
options?: UseDocumentOptions
382-
): Ref<_InferReferenceType<T> | null> | Ref<T | null> {
383-
const data = ref<T | null>(null)
382+
): _RefWithState<_InferReferenceType<T> | null> | _RefWithState<T | null> {
383+
const data = ref<T | null>(null) as Ref<T>
384+
const pending = ref(true)
385+
// TODO: can this error type come from firebase?
386+
const error = ref<Error>()
384387

385388
let unbind!: ReturnType<typeof bindDocument>
386389
const promise = new Promise((resolve, reject) => {
387390
unbind = bindDocument(data, documentRef, ops, resolve, reject, options)
388391
})
392+
promise
393+
.catch(reason => {
394+
error.value = reason
395+
})
396+
.finally(() => {
397+
pending.value = false
398+
})
389399

390400
// TODO: refactor in a function
391401
if (getCurrentScope()) {
@@ -396,8 +406,40 @@ export function useDocument<T>(
396406
})
397407
}
398408

409+
Object.defineProperties(data, {
410+
error: {
411+
get: () => error,
412+
},
413+
data: {
414+
get: () => data,
415+
},
416+
pending: {
417+
get: () => pending,
418+
},
419+
promise: {
420+
get: () => promise,
421+
},
422+
unbind: {
423+
get: () => unbind,
424+
},
425+
})
426+
399427
// no unwrapRef to have a simpler type
400-
return data as Ref<T | null>
428+
return data as _RefWithState<T>
429+
}
430+
431+
/**
432+
* @internal
433+
*/
434+
export interface _RefWithState<T> extends Ref<T> {
435+
get data(): Ref<T>
436+
get error(): Ref<Error | undefined>
437+
get pending(): Ref<boolean>
438+
439+
// TODO: is it really void?
440+
promise: Promise<void>
441+
// TODO: extract type from bindDocument and bindCollection
442+
unbind: () => void
401443
}
402444

403445
export const unbind = (target: Ref, reset?: FirestoreOptions['reset']) =>

tests/firestore/document.spec.ts

+5
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,10 @@ describe('Firestore collections', () => {
6262
expectType<Ref<number | null>>(useDocument(refWithConverter))
6363
// @ts-expect-error
6464
expectType<Ref<string | null>>(useDocument(refWithConverter))
65+
66+
// destructuring
67+
expectType<Ref<DocumentData | null>>(useDocument(itemRef).data)
68+
expectType<Ref<Error | undefined>>(useDocument(itemRef).error)
69+
expectType<Ref<boolean>>(useDocument(itemRef).pending)
6570
})
6671
})

0 commit comments

Comments
 (0)