T
TanStack7mo ago
optimistic-gold

[SOLVED] Typescript issues with infinitequery and initial data

Typescript playground: https://www.typescriptlang.org/play/?#code/JYWwDg9gTgLgBDAnmApnA3nAqgZxQSQDsAzYQ4GFARQFcUpEB5MGYCQnAGjlvsQGkUiOAF84xKBBBwA5AAEYAQw5KAxgGsA9FBSLVMALQBHOgxkBuALAAoUJFgY4NPEVLlKvBqPGTp8pSp6Wjp6hiZ8FjZ20PDoIPQA5ihiElJwAEQANhAAJoo4ABbpNjZIqHAAIopKcAC8GMA5AFxwODBQZAkiJdaq7G1wqiEeLDh1cAAU4QzMrP0tjCAUADy4BCRkFNSmTCxsHMtVSgDaALoAfNwy0wJCMnAAPrJJMAByKAAeMAAKikm-UEUIHuTxkm1Yikyv3+ikBwPO43QIgAlHUEegbHA4DoYDQoIQ4PEoEkJhjrFisTdBIgWsdrjtqTJTpxMRSbgAxQhNCao2oIs5wfKVaqKM4s8kU8HASHQlAAoEtACM4opcBe7y+svlIBaPLRcEINEymRVkvc0syR0ULTJqqxYD+KBwtOZrNVDphcOdcDObtErLEQrWrnB2z4s32OEOIrOlzgNwj-TgyJs3WsNj6KgweSUYnqznWbi2nkQEyGuhGMBwPJT6esmk0g368DckKt4xzigAdB6nXBlgZBwY4ABRKCSKAZ5viMhtkUdkVAA
import type { UseInfiniteQueryOptions, QueryKey } from '@tanstack/react-query';
import { useInfiniteQuery } from '@tanstack/react-query';
import {merge} from "lodash"

type Data = {id: string}

const createQpts = (queryOptions: Omit<UseInfiniteQueryOptions<Data[]>, 'queryKey' | 'getNextPageParam' | 'initialPageParam'> = {}) => {
return merge({
queryKey: ['queryKey'],
queryFn:() => [] as Data[],
initialPageParam: 1,
getNextPageParam: () => null,
initialData: {
pages: [],
pageParams: []
}
} as UseInfiniteQueryOptions<Data[]>, queryOptions )
}

const {data} = useInfiniteQuery(createQpts())

// const finalData = data.pages <---- Error
const finalData = data
import type { UseInfiniteQueryOptions, QueryKey } from '@tanstack/react-query';
import { useInfiniteQuery } from '@tanstack/react-query';
import {merge} from "lodash"

type Data = {id: string}

const createQpts = (queryOptions: Omit<UseInfiniteQueryOptions<Data[]>, 'queryKey' | 'getNextPageParam' | 'initialPageParam'> = {}) => {
return merge({
queryKey: ['queryKey'],
queryFn:() => [] as Data[],
initialPageParam: 1,
getNextPageParam: () => null,
initialData: {
pages: [],
pageParams: []
}
} as UseInfiniteQueryOptions<Data[]>, queryOptions )
}

const {data} = useInfiniteQuery(createQpts())

// const finalData = data.pages <---- Error
const finalData = data
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
14 Replies
frail-apricot
frail-apricot7mo ago
This sorta works but I'm not sure I'd advise it
import { infiniteQueryOptions, useInfiniteQuery } from '@tanstack/react-query';
import { merge } from "lodash"

type Data = {id: string}

type QueryOptions<T> = Parameters<typeof infiniteQueryOptions<T[]>>

function createQpts<TData>(queryOptions: Partial<Omit<QueryOptions<TData>, 'queryKey' | 'getNextPageParam' | 'initialPageParam'>> = {}) {
return merge(infiniteQueryOptions<TData[]>({
queryKey: ['queryKey'],
queryFn:() => [],
initialPageParam: 1,
getNextPageParam: () => null,
initialData: {
pages: [],
pageParams: []
}
}), queryOptions);
}

const { data } = useInfiniteQuery(createQpts<Data>());

// const finalData = data.pages <---- Error
const finalData = data?.pages
import { infiniteQueryOptions, useInfiniteQuery } from '@tanstack/react-query';
import { merge } from "lodash"

type Data = {id: string}

type QueryOptions<T> = Parameters<typeof infiniteQueryOptions<T[]>>

function createQpts<TData>(queryOptions: Partial<Omit<QueryOptions<TData>, 'queryKey' | 'getNextPageParam' | 'initialPageParam'>> = {}) {
return merge(infiniteQueryOptions<TData[]>({
queryKey: ['queryKey'],
queryFn:() => [],
initialPageParam: 1,
getNextPageParam: () => null,
initialData: {
pages: [],
pageParams: []
}
}), queryOptions);
}

const { data } = useInfiniteQuery(createQpts<Data>());

// const finalData = data.pages <---- Error
const finalData = data?.pages
Reusability can definitely be better
optimistic-gold
optimistic-goldOP7mo ago
Thanks, the idea is to use typeof infiniteQueryOptions instead of useInfiniteQueryOptions if you are free please share your ideas on that !!
frail-apricot
frail-apricot7mo ago
It sort of depends what you're trying to do, but I personally find that helpers around the queryOptions()/infiniteQueryOptions() functions tend to be hard to get right for little benefit
optimistic-gold
optimistic-goldOP7mo ago
I wanna mostly use it because, the underlying queryFn supports for predictable api params or wait not that
frail-apricot
frail-apricot7mo ago
I mean, that's not necessarily true… I tend to use helpers too but they're tied to a specific query and basically define everything necessary for that one query, rather than have 1 super generic and reusable helper
optimistic-gold
optimistic-goldOP7mo ago
I can do createQpts<Data>().queryKey to prefetch the query data during the app start also i can pass initialData to the createQpts
frail-apricot
frail-apricot7mo ago
for example, for a "users" query I'll do something like this
function getUsersQueryOptions(filter: …) {
return queryOptions({
queryKey: ['users', filter],
queryFn: () => fetch('/api/users?filter=…'),
// Other relevant options
});
}
function getUsersQueryOptions(filter: …) {
return queryOptions({
queryKey: ['users', filter],
queryFn: () => fetch('/api/users?filter=…'),
// Other relevant options
});
}
And in places where I want to fetch users I'll then do
const queryResult = useSuspenseQuery(getUsersQueryOptions(filter));
const queryResult = useSuspenseQuery(getUsersQueryOptions(filter));
optimistic-gold
optimistic-goldOP7mo ago
yeah i do something like this as well but then if i wanna set the query with initial data, the one i device comes very handy
frail-apricot
frail-apricot7mo ago
Yeah I guess.. but you'll have to leverage TypeScript generics to type the underlying queryoptions correctly
optimistic-gold
optimistic-goldOP7mo ago
not necessarily, that will be abstracted to the createQOpts function right.
frail-apricot
frail-apricot7mo ago
And those tend to be tricky to get right... my initial code snippet above for example is technically also incorrect because infiniteQueryOptionscan take a union of 3 different shapes (one with initialData, one without, and one other I forgot), stuff like that tends to mess with your types Anyway, personal preference I guess, if it works well for you all the better 🙂
optimistic-gold
optimistic-goldOP7mo ago
yeah tanstack query kinda hard to use with very very proper types this is something i already have oh yeah now i remember the reason for abstracting it as createQOpts I can now use queryClient.fetchQuery as well as useQuery({}) this way i can abstract non reactive code outside my react components and then i can use it for prefetching as well in the start of my app
frail-apricot
frail-apricot7mo ago
yeah definitely, also the main reason I use my helpers like getUsersQueryOptions, especially when you combine react-query with a router where you want to preload in a loader it's super helpful to just reuse the same helper func
optimistic-gold
optimistic-goldOP7mo ago
yeah thanks @pleunv !

Did you find this page helpful?