Unexpected behaviour when returning `defer()` value without wrapping in an object
Describe the bug
When returning a deferred promise from the route loader() the promise isn't actually deferred, but it seems awaited. This can be seen on the resolved type depending on whether the defer() value was returned directly vs. when it's wrapped inside an object.
This works:
loader: () => {
return {
deferredPromise: defer(new Promise<string>(() => {})),
}
}
const data = Route.useLoaderData() // ✅ type for `data.deferredPromise` is correctly `DeferredPromise<string>`
This does not work:
loader: () => {
return defer(new Promise<string>(() => {}))
}
const deferredPromise = Route.useLoaderData() // ❌ type for `deferredPromise` is unexpectedly `string` instead of `DeferredPromise<string>`
Your Example Website or App
https://stackblitz.com/edit/tanstack-router-hbzw42?file=src%2Froutes%2Fposts.%24postId.tsx
Steps to Reproduce the Bug or Issue
- Open the
routes/posts/posts.$postId.tsxfile - Check out the comments in the loader
- Observe the difference between the types from
Route.useLoaderData()depending on whether adefer(...)value is returned directly vs. when it's wrapped in an object, e.g.{ deferredPromise: defer(...) }
Expected behavior
I expect the loaderData value for the defer(...) value to always be a DeferredPromise<>, not the value of said DeferredPromise.
Screenshots or Videos
Platform
- OS: macOS + Arc 1.47
Additional context
No response
does returning a "blank" DeferredPromise even work correctly at runtime?
Not when directly returned, but it does when wrapped in an object. The blank promise is only for illustration/repro.
Looked into this, when you directly return defer from the loader, at runtime it resolves it before rendering the component, therefore, the string type is correct there. This may have something to do with essentially returning a Promise from the loader, which is resolved.
This is contrasted to returning an Object with defer Promises as values, where the return value of the loader is an object and not a Promise, therefore, the loaderData type correctly resolves to DeferredPromise.
To change the type signature would require changing the existing runtime behaviour. Right now, given that all the examples show the defer being returned as part of an object, I don't see this being a goal at the moment.
If you want this to be changed, please open a new issue referencing this issue asking for this change/enhancement which can then be discussed with Tanner.
Closing this for now, as the types being resolved are correct as it is what's being currently returned at runtime.