fix(db): restore query typechecking for generic collection row types#1678
Conversation
…nStack#1677) Queries over a Collection<T> where T is an unresolved generic type parameter stopped typechecking in 0.6.6: refs inside where/join/select callbacks resolve to a union including RefLeaf, which exposes no row properties, even ones guaranteed by T's constraint. These tests currently fail and should pass once the ref typing is fixed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes TanStack#1677. Since 0.6.6, refs inside where/join/select callbacks broke when the collection's row type is an unresolved generic type parameter: TypeScript defers the IsPlainObject conditional in RefForContextValue and degrades the ref to a union that includes RefLeaf, which exposes no row properties. Two changes: - Make RefForContextValue distribute over T so that, when deferred, TypeScript resolves its constraint by instantiating T with T's own constraint, picking the Ref branch instead of the Ref | RefLeaf union. - Use GetRawResult instead of GetResult in SchemaFromSource for subquery sources: GetResult's Prettify wrapper produces a mapped type that the conditional-constraint resolution above cannot see through. Final query results still go through GetResult, so IDE display is unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
📝 WalkthroughWalkthroughUpdates query-builder schema inference for subqueries and adds compile-time regression tests for generic collection row-property access and generic subquery joins. A patch changeset documents the fix. ChangesGeneric collection typing
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
KyleAMathews
left a comment
There was a problem hiding this comment.
Verified the reported #1677 regression and the PR's three type-test cases: generic where callbacks, select callbacks, and generic subqueries used as join sources. The implementation is appropriately scoped and the broader nullable/union constraint-propagation work is now documented in #1679. Approving this as a valid incremental regression fix.
More templates
@tanstack/angular-db
@tanstack/browser-db-sqlite-persistence
@tanstack/capacitor-db-sqlite-persistence
@tanstack/cloudflare-durable-objects-db-sqlite-persistence
@tanstack/db
@tanstack/db-ivm
@tanstack/db-sqlite-persistence-core
@tanstack/electric-db-collection
@tanstack/electron-db-sqlite-persistence
@tanstack/expo-db-sqlite-persistence
@tanstack/node-db-sqlite-persistence
@tanstack/offline-transactions
@tanstack/powersync-db-collection
@tanstack/query-db-collection
@tanstack/react-db
@tanstack/react-native-db-sqlite-persistence
@tanstack/rxdb-db-collection
@tanstack/solid-db
@tanstack/svelte-db
@tanstack/tauri-db-sqlite-persistence
@tanstack/trailbase-db-collection
@tanstack/vue-db
commit: |
This restores TypeScript query-builder support for collections whose row type is an unresolved generic parameter. Generic
where,select, and subquery join-source callbacks once again expose fields guaranteed by the generic constraint, fixing the regression introduced in v0.6.6.Root cause
The query builder decides whether a callback value should be represented as a property-bearing
Refor an opaqueRefLeafthrough a conditional type. For an unresolved generic such asT extends { id: string }, the conditional was deferred into a union containing both possibilities. BecauseRefLeafhas no row properties, TypeScript rejected access to fields such asideven though the generic constraint guarantees them.Subquery sources had an additional mapped
Prettifylayer that prevented TypeScript from resolving the generic constraint through the ref conditional.Approach
RefForContextValuedistributive so TypeScript can evaluate the ref shape through the generic constraint.GetRawResultfor internal subquery schemas, while retainingGetResultfor final user-facing result types.where, directselect, and generic subqueries used as join sources.Key invariants
T extends { id: string }must exposeidinside supported query callbacks.Non-goals
This PR restores the three cases reported in #1677. Broader generic-constraint propagation through nullable joined aliases and both forms of
unionAllis tracked separately in #1679; resolving those cases safely requires additional type-system work and must preserve existing heterogeneous union and join inference.Trade-offs
GetRawResultis used only on the internal subquery schema path. Final results continue to use the prettified representation, avoiding a user-facing type-display regression.Verification
The new type tests were added first and verified RED against the regressed implementation, then GREEN after the fix.
pnpm --filter @tanstack/db testFiles changed
packages/db/src/query/builder/types.ts— preserves generic constraints through callback ref and subquery schema construction.packages/db/tests/query/generic-collection.test-d.ts— covers generic filtering, selection, and subquery join sources..changeset/generic-row-type-refs.md— records the patch release impact.Fixes #1677
Follow-up: #1679