-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
fix: type issue when void or undefined is returned from query function #3541
fix: type issue when void or undefined is returned from query function #3541
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 6984adc:
|
thank you for the contribution 🙌 . Could you maybe add some type-level tests for useQuery and useInfiniteQuery that assure that the types work as expected, so that we can't inadvertently break them. A good starting point would be around here for useQuery: and here for useQueries: also, something doesn't compile at the moment:
|
@TkDodo Yes I see. A lot of code and complex types has been build on top of the assumption that the |
@TkDodo In the meantime, some questions have been arisen: 1st: A lot of test cases use a query function with return type const queryFn = () => Promise.reject('<error>') // typeof queryFn = () => Promise<never> Is this a valid use case for const queryFn = ():Promise<unknown> => Promise.reject('<error>') // pleases tsc 2nd: In the end what the compiler tells the user is something like 3rd: At some locations in the codebase E.g. setQueryDefaults(
queryKey: QueryKey,
options: QueryObserverOptions<unknown, unknown, any, any> // change first two generics from any to unknown
): void {
const result = this.queryDefaults.find(
x => hashQueryKey(queryKey) === hashQueryKey(x.queryKey)
)
if (result) {
result.defaultOptions = options
} else {
this.queryDefaults.push({ queryKey, defaultOptions: options })
}
} |
…ction return type to comply with new QueryFunction type
…ts from string to unknown
Types for Regarding |
Hi @yss14 , thanks for jumping on this 💪 On the type InvalidQueryFn = QueryFunction<undefined | Promise<undefined> | Promise<undefined> | void | Promise<void>> something like this - artysidorenko@10f5585. Let me know what you think. sidenote: interestingly, I think TS will make this kinda thing easier to deal with in the next version by allowing us to specify constraints on infer clauses. quote from the PR: "If you are testing multiple other conditions, this could result in an unmanageable branching structure which results in the need to define additional type aliases for repeated branches" which feels like what's going on here 😅 |
If possible, I think we should allow |
@TkDodo Thanks for the reply. I was thinking a lot about it during the past days and I guess the "bad" news is that this would not be possible at the moment. Regarding your use case of failing query functions in code sandboxes, I guess there is an easy fix to make it work in the future: - useQuery(['key'], () => Promise.reject(new Error('Some error')))
+ useQuery(['key'], () => Promise.reject<unknown>(new Error('Some error'))) Furthermore, I implemented the suggested solution for Would appreciate a first code review of both of you guys :) |
…nto fix/query-function-data-dont-accept-promise-undefined
@TkDodo I rebased my branch with latest upstream How can I run test cases locally? Executing |
Oh you get those errors locally, too? So weird, I've been having these for months - so from before the esm bundling changes. I found no way to fix it except doing a clean checkout to a new directory - then it works again. Sadly I have no clue how to properly fix it - maybe you do? |
Codecov Report
@@ Coverage Diff @@
## beta #3541 +/- ##
=======================================
Coverage 96.93% 96.93%
=======================================
Files 47 47
Lines 2381 2381
Branches 709 709
=======================================
Hits 2308 2308
Misses 71 71
Partials 2 2
Continue to review full report at Codecov.
|
@TkDodo I think #3521 fixed the issue. It seems like the issue was caused by separate |
@yss14 thanks, that sounds like it could be the issue. I'm not getting it at the moment, but I also think it happened when switching between master / beta, which I have been doing a lot recently 😅 . Can't wait to finally release v4 🙌 |
🎉 This PR is included in version 4.0.0-beta.9 🎉 The release is available on: Your semantic-release bot 📦🚀 |
@TkDodo @yss14 I'm struggling with this update, maybe you can help me with that, it seems like I'm missing some point, but I don't know where) so, I have a query that goes like
|
@markivancho |
@TkDodo I guess we should add some notes to the breaking change log of v4 migration guide? |
@yss14 this looks like a regression imo. Is there any way we can allow |
@TkDodo I don't think so, since If there are scenarios where the query function returns const fetchAnyData = (): Promise<any> => Promise.resolve()
function SomePage(){
useQuery<unknown>(['mydata'], () => fetchAnyData()) // no typescript error
} So in the end this change is a regression, since we restricted the allowed type space of the query function return type by "removing" |
I see. Personally, I think it's still a good change. The problem is if you just use:
it will still default to
which is fine and will still work. I'm inclined to keep the change, because returning
what do you think? |
thanks, after further digging, my actual problem was
With this code, typescript complains after changing by the way, it would be very nice if you could include in the react-query + typescript docs best practices regarding generics usage |
I'll try to improve the docs. In the meantime, have a read here: https://tkdodo.eu/blog/react-query-and-type-script |
@TkDodo thanks! your blog is a golden mine of react-query |
@yss14 here is another reproduction that works fine on v3, but fails on v4: https://codesandbox.io/s/serene-panini-6o70bk?file=/src/hooks/useApi.ts |
@TkDodo Thanks, I will work on a follow-up PR in the coming days regarding migration docs and typescript docs, as well as tackling the reproduction example you provided. |
@TkDodo A little update from my side. I'm still investigating why typescript is complaining here, since your abstract data fetcher example looks fine to me. I already posted some question in r/typescript and the FullStackTypeScript Slack Community in hope anyone can give me some hint. I also boiled down the use case into a minimal typescript playground Maybe @artysidorenko has some clue why typescript is complaining here? :) |
Hi @yss14, yeah your first example passes because TS sees a Not ideal, but if we want to keep those undefined/void constraints in place, then one workaround for now could be to re-use the here's what it looks like forking the codesandbox
|
@artysidorenko would it maybe bet helpful to extract |
@artysidorenko another thing that might be a bit weird is that I can't return Error is:
While I'm all for avoiding leaking anys like that, I think it goes a bit against the mantra of "the queryFn just needs to return a Promise to work". I'm not sure this is doable with the current types though, but not even With that in mind, do you think it would be better to just remove the type level check again? |
Hi @TkDodo yeah, I think I agree with you. While I'm able to fix that particular ... I keep finding more and more edge cases that throw inconsistent results - for example the above solution doesn't work for Am mindful that you'll probably keep getting more and more of these issues reported, generating a lot of noise. I'll put up a PR to remove the type-check later this weekend if there's no other opposition to that. *longer term will see if it's possible to think of all the edge cases and potentially bring it later if we feel confident, but don't have an ETA on that |
yes please, that would be ideal. I'm totally fine with adding that stricter type checks later if we get to a solution that we all agree upon 👍 |
Resolves #3516
Problem with current implementation is that
T | Promise<T>
is passed toQueryFunctionData<T>
intypes.ts
, butPromise<T>
does not extendundefined
, so in that case the conditional type fails its intent.