fix: update useFirestoreDocData return type to include undefined - #733
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates type definitions across several files. It replaces JSX.Element with React.ReactElement in auth.tsx, performance.tsx, and storage.tsx, and adds an explicit React.ReactElement return type in sdk.tsx. Additionally, it updates the return types of useFirestoreDocData and useFirestoreDocDataOnce in firestore.tsx to allow undefined values (ObservableStatus<T | undefined>). There are no review comments, and I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
docData() from rxfire returns Observable<T | undefined> because a Firestore document may not exist. The previous ObservableStatus<T> return type was a lie — callers would get undefined at runtime with no type-level warning. Fixes FirebaseExtended#577
11e645d to
2bdb63a
Compare
…ebaseExtended#733) * fix: update useFirestoreDocData return type to include undefined docData() from rxfire returns Observable<T | undefined> because a Firestore document may not exist. The previous ObservableStatus<T> return type was a lie — callers would get undefined at runtime with no type-level warning. Fixes FirebaseExtended#577 * docs: regenerate API reference after ObservableStatus type fix
Exploratory work toward the half of FirebaseExtended#749 the gate currently hands to a human: is a .d.ts change additive or breaking. Nothing here runs in CI. Committed so the design work survives, and so the findings are attached to the code that produced them. Approach: let tsc adjudicate assignability rather than hand-rolling subtyping. For every symbol exported by both versions, emit probe lines asserting assignability in each direction, compile, read the errors. About 3.4s for the whole package. Correct on every real version pair, including concluding unprompted that 4.2.6 is still breaking relative to 4.2.3 and that the reason is exactly the two hooks FirebaseExtended#733 changed. 4.2.3 -> 4.2.4 reduces 39 raw failures to one root cause, ObservableStatus. Four findings worth keeping, each caught by a control rather than by reading the code: - Classes with private members are nominally typed, so two copies are never assignable and 4.2.6 compared as breaking against itself. Comparing a version to itself is the cheapest available control. - Root attribution has to walk non-exported types, or nine symbols look like independent roots while their declarations are byte-identical. - Only new->old failing means a consumer break. The other direction alone means the API got more permissive. - Generic constraints cannot be synthesised away, and instantiating with any/unknown hides the very break this exists to catch. Also settles a question that was open: this composes with the gate's textual .d.ts diff rather than replacing it. Adding an optional property is invisible to assignability but is still a semver minor, so the diff answers "did anything change" and this answers "is it breaking". Known gaps are listed in the README: the private-member stripping is a line regex rather than an AST walk, and local types are keyed by bare name so cross-file collisions can mis-attribute a root.
Exploratory work toward the half of FirebaseExtended#749 the gate currently hands to a human: is a .d.ts change additive or breaking. Nothing here runs in CI. Committed so the design work survives, and so the findings are attached to the code that produced them. Approach: let tsc adjudicate assignability rather than hand-rolling subtyping. For every symbol exported by both versions, emit probe lines asserting assignability in each direction, compile, read the errors. About 3.4s for the whole package. Correct on every real version pair, including concluding unprompted that 4.2.6 is still breaking relative to 4.2.3 and that the reason is exactly the two hooks FirebaseExtended#733 changed. 4.2.3 -> 4.2.4 reduces 39 raw failures to one root cause, ObservableStatus. Four findings worth keeping, each caught by a control rather than by reading the code: - Classes with private members are nominally typed, so two copies are never assignable and 4.2.6 compared as breaking against itself. Comparing a version to itself is the cheapest available control. - Root attribution has to walk non-exported types, or nine symbols look like independent roots while their declarations are byte-identical. - Only new->old failing means a consumer break. The other direction alone means the API got more permissive. - Generic constraints cannot be synthesised away, and instantiating with any/unknown hides the very break this exists to catch. Also settles a question that was open: this composes with the gate's textual .d.ts diff rather than replacing it. Adding an optional property is invisible to assignability but is still a semver minor, so the diff answers "did anything change" and this answers "is it breaking". Known gaps are listed in the README: the private-member stripping is a line regex rather than an AST walk, and local types are keyed by bare name so cross-file collisions can mis-attribute a root.
Problem
useFirestoreDocDataanduseFirestoreDocDataOncewere declared to returnObservableStatus<T>, butdocData()from rxfire returnsObservable<T | undefined>because a Firestore document may not exist. This meant callers could accessdata.somePropertywithout any type-level warning, only to get a runtime error whendatawasundefined.Fix
Update the return types to
ObservableStatus<T | undefined>, which accurately reflects what the observable emits. The discriminated union inObservableStatusalready handles this correctly —status: 'loading'hasdata: undefined,status: 'success'hasdata: T | undefinedfor these hooks.TypeScript now correctly flags:
Fixes #577