🏷️ Interface and Typings Improvements. - #154
KingDarBoja wants to merge 15 commits into
Conversation
armando-navarro
left a comment
There was a problem hiding this comment.
Hey @KingDarBoja, thanks for submitting this. I found four things blocking approval, and the rest is optional.
Blocking: traceUntilFirst changed behavior
In performance/index.ts the rewrite ends the trace in the complete handler:
tap({
complete: () => traceSubscription.unsubscribe(),
}),- On
mainthat unsubscribe is thenexthandler, so the trace ends at the first value, which is what the docblock describes. - With this change it ends only when the source completes, which for a Firestore listener is never, and the operator becomes identical to
traceUntilCompleteright above it. - Your #123 branch had
next:here, so I think this slipped in while re-authoring. Changingcomplete:back tonext:restores it. I ran all five operators through a jest spec that stubswindow.performance, and the other four behave the same as onmain.
Nothing in test/ covers the performance module, which is why the test jobs stayed green. A spec is not required for this PR, but if you do add one:
import ... from '../performance'resolves through that folder'spackage.jsonto the builtdist.- Import from
../dist/performanceinstead, the way the other suites do.
Blocking: the Lint job
The 36 errors are all indentation or trailing whitespace, and yarn lint:fix clears every one of them with whitespace-only changes.
Blocking: collectionCountSnap now hands back a lite query
The full module's collectionCountSnap is typed with the lite SDK's AggregateQuerySnapshot:
firestore/collection/index.tsimportsCountSnapshotfrom../lite/interfaces(that import predates you), sosnap.queryis a liteQuery.- On
mainthat was hidden because the model slot wasany. - With
AppModelTypefilled in, existing callers that usesnap.querywith the full SDK stop compiling.
Against a Query<Folk>:
(await getDocs(snap.query)).docs[0].data()is nowFolk | {name: string | FieldValue}instead ofFolk.query(snap.query, limit(1))is no longer aQuery<Folk>.- rxfire's own
collectionData(snap.query)no longer emitsFolk[].
All three compile on main. The fix that worked for me, on firebase 10 and 12: define the alias for the full module in firestore/interfaces.ts and import it from there instead of the lite file.
export type CountSnapshot<
AppModelType = DocumentData,
DbModelType extends DocumentData = DocumentData,
> = import('firebase/firestore').AggregateQuerySnapshot<
{count: import('firebase/firestore').AggregateField<number>},
AppModelType,
DbModelType
>;Blocking: the two-parameter lite Query alias under firebase 9
package.json still supports firebase 9, and firebase 9's lite SDK declares Query<T> with one parameter. Consumers compile against rxfire's emitted declarations, and with skipLibCheck on, under firebase 9 the new lite.Query<AppModelType, DbModelType> alias resolves to an error type there. The effect is silent:
- Against
main's declarations, a firebase 9 project gets errors forcollectionData(notAQuery),collection(notAQuery), and a wrong element type. - Against this branch's declarations, the same file compiles with no errors, and every lite function typed with
Query<T>accepts anything.
What worked for me on firebase 9, 10 and 12:
- Keep
export type Query<T> = lite.Query<T>;. - Give the two lite count functions the same one-parameter shape as the full module ones (
Query<AppModelType>in,CountSnapshot<AppModelType>out). CountSnapshotcan keep both parameters: itsDbModelTypedefaults toDocumentData, and its firebase 9 problem is the pre-existing one from #94.
If you would rather drop firebase 9 from the peer range instead, that is a separate decision that would go in its own PR.
Optional: the new test under tsc
The docData converter test only compiles because jest runs through babel, which strips types without checking them.
tscovertest/firestore.test.tsrejects it:Type '"UID"' is not assignable to type '"name"'.- The reason is the signature
docData<T, R extends T = T>withidField?: keyof R. With the converter,TisFolk, so the only legal key isname. - Passing the generics fixes it and drops both casts from the test:
const unwrapped = docData<Folk, Folk & {UID: string}>(davidDoc.withConverter(Folk), {idField: 'UID'});
unwrapped.pipe(take(1)).subscribe((val) => {
expect(val).toBeInstanceOf(Folk);
expect(val).toEqual(expect.objectContaining({name: 'David', UID: 'david'}));
done();
});Optional: smaller things
-
firestore/lite/collection/index.ts: theas Promise<CountSnapshot<AppModelType, DbModelType>>cast ongetCount(query)is not needed.getCountalready returns that type, and it compiles without the cast on firebase 10, 11 and 12. -
firestore/document/index.ts: the two casts in(data as Record<string, unknown>)[options.idField as string] = snapshot.idcan go.Object.assign(data, {[options.idField]: snapshot.id});type-checks and behaves the same. -
The lite module's
snapToDatafollows the same write-in-place rule but has no converter-plus-idFieldtest and no comment saying why. That is how the full copy went back to a spread in a 2022 return-type fix (ab8fe07) without anyone noticing until #93. A copy of your new test intest/firestore-lite.test.tswould keep it from happening again. -
traceUntilandtraceWhile: since the PR rewrites thosenexthandlers anyway,(a) => test(a)could become(value) => test(value). -
docs/storage.mdline 100 still listsgetMetadata()as returningObservable<Object>, and the docs folder ships in the package.Observable<import('firebase/storage').FullMetadata>matches the rows below it. The description above it also says "emits the URL of the file's metadta", which was wrong before you got here. -
Please add
Fixes #93to the description, since this resolves it. One behavior note worth a sentence there too: withidField, rxfire now writes onto the object the converter returned, so a converter that returns a frozen object throws where the spread used to copy it (the lite module already works that way).
On the workflow question in your description:
- GitHub decides whether a fork PR's runs need approval per pull request, from the contributor's status under the repo's Actions settings, not per workflow file, so moving the test job to its own file would not change it.
- Unless the repo is set to require approval for all external contributors, the requirement ends once you have a merged PR, which this one will be.
Thanks again. If I have misread the traceUntilFirst change, tell me and I will look again.
docData and collectionData now uses `keyof` for idField option.
|
Alright, I believe I have made all the changes (even the optional ones) from your feedback. @armando-navarro |
As promised, I made a new branch containing only the type changes from my previous PR.
Feedback Changes - September 17.
Fixes #93.
📓 Take into account that with
idField, rxfire now writes onto the object the converter returned, so a converter that returns a frozen object throws where the spread used to copy it.Original Post
By the way, I managed to run the GH action for
testandbuildlocally using Nektos/act tool along with Docker so I could see the test suite results against the test matrix.I really think the test suite workflow should be apart so it is easier to lookup at test results on pull requests so contributors do not have to wait for a maintainer to approve the jobs...