-
Notifications
You must be signed in to change notification settings - Fork 129
Improve error when returning undefined in useLiveSuspenseQuery #860
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Improve error when returning undefined in useLiveSuspenseQuery #860
Conversation
- Add overloads to support query functions that can return undefined/null
- Update implementation to return undefined values instead of throwing error when query is disabled
- Add tests for conditional query pattern with undefined
- Mirrors useLiveQuery behavior for consistency
This allows conditional queries like:
```ts
useLiveSuspenseQuery(
(q) => userId
? q.from({ users }).where(({ users }) => eq(users.id, userId)).findOne()
: undefined,
[userId]
)
```
Following TanStack Query's useSuspenseQuery design philosophy, disabled queries are intentionally not supported to maintain the type guarantee that data is T (not T | undefined). Changes: - Revert type overloads that allowed undefined/null returns - Keep error throw when query callback returns undefined/null - Improve error message with clear guidance on alternatives: 1. Use conditional rendering (don't render component until ready) 2. Use useLiveQuery instead (supports isEnabled flag) - Update tests to expect error instead of undefined values - Update changeset to document the design decision and alternatives This matches TanStack Query's approach where Suspense queries prioritize type safety and proper component composition over flexibility.
🦋 Changeset detectedLatest commit: fbed864 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
More templates
@tanstack/angular-db
@tanstack/db
@tanstack/db-ivm
@tanstack/electric-db-collection
@tanstack/offline-transactions
@tanstack/powersync-db-collection
@tanstack/query-db-collection
@tanstack/react-db
@tanstack/rxdb-db-collection
@tanstack/solid-db
@tanstack/svelte-db
@tanstack/trailbase-db-collection
@tanstack/vue-db
commit: |
|
Size Change: 0 B Total Size: 85.8 kB ℹ️ View Unchanged
|
|
Size Change: 0 B Total Size: 3.34 kB ℹ️ View Unchanged
|
Add detailed @remarks section that appears in IDE tooltips to clearly explain that disabled queries are not supported and provide two alternative solutions: 1. Use conditional rendering (recommended pattern) 2. Use useLiveQuery instead (supports isEnabled flag) Includes clear examples showing both ❌ incorrect and ✅ correct patterns. This provides immediate guidance when users encounter the type error, without requiring complex type-level error messages that can be fragile. TypeScript's natural "No overload matches this call" error combined with the JSDoc tooltip provides a good developer experience.
Add 'poison pill' overloads that return DisabledQueryError type with custom error message embedded via unique symbol. This is experimental to evaluate if it provides better DX than JSDoc alone. Still evaluating trade-offs before finalizing approach.
The key insight: make the implementation signature return type a union
that includes both DisabledQueryError and the valid return types.
TypeScript requires overload signatures to be compatible with the
implementation signature. By using a union type:
DisabledQueryError | { state: any; data: any; collection: any }
We satisfy TypeScript's compatibility requirement while still catching
invalid patterns at compile time.
What users experience:
1. Type error when returning undefined → DisabledQueryError inferred
2. Property access errors: "Property 'data' does not exist on type 'DisabledQueryError'"
3. IDE tooltip shows custom error message embedded in the type
4. Compilation fails (forces fix)
This provides BOTH:
- JSDoc documentation (in tooltips)
- Active type-level errors with custom messaging
…ive-query-01WbQnMBXpdfUeD3tQi1YV82
The poison pill overloads were matching BEFORE the specific overloads, causing TypeScript to infer DisabledQueryError for valid queries. TypeScript checks overloads top-to-bottom and uses the first match. Since QueryBuilder is assignable to QueryBuilder | undefined | null, the poison pill overloads were matching first. Solution: Move poison pill overloads to the END, just before the implementation. This ensures: 1. Specific overloads (without undefined) match first 2. Poison pill overloads (with undefined) only match when needed All tests now pass with no type errors.
samwillis
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pulled this locally as I wanted to see what the "poison pill" overload would do, and particularly how it would show in an editor. It seems that it just removes the type error, and then when you scroll down (when mouse-overing the hook) you see the suggestion this will not work - see video below.
This means that while previously (see the second image) we would have a type error if the hook tried to return undefined, now it doesn't throw a type error at all.
The runtime error this pr adds looks good, but I think the new type error is a worse option than an unfortunate but correct type error.
Video showing how the new "poison pill" overload works in an editor:
Screen.Recording.2025-11-25.at.13.18.46.mov
This is on main with the same change:
Make it clear this isn't supported and they should use
useLiveQueryinstead.