Dani;
Dani;3y ago

data becomes never[] when destructuring with a fallback value

Currently it doesn't seem possible to set a fallback value on a destructured data property, for example:
const { data = [] } = trpc.useQuery(['company.listIds']);
// expecting data to be the inferred type { id: string }[] but instead it's never[]


// This somehow works
const query = trpc.useQuery(['company.listIds']);
const { data = [] } = query;
// data is correctly typed as { id: string }[]
const { data = [] } = trpc.useQuery(['company.listIds']);
// expecting data to be the inferred type { id: string }[] but instead it's never[]


// This somehow works
const query = trpc.useQuery(['company.listIds']);
const { data = [] } = query;
// data is correctly typed as { id: string }[]
The "equivalent" with pure react-query:
interface Company {
id: string;
}
const { data = [] } = useQuery<Company[]>(['company.listIds'], someFetchFunction);
// data is correctly typed as Company[]
interface Company {
id: string;
}
const { data = [] } = useQuery<Company[]>(['company.listIds'], someFetchFunction);
// data is correctly typed as Company[]
Does anyone know if there's a way to achieve the same behaviour of react-query in @trpc/react?
13 Replies
julius
julius3y ago
You can use the initialData prop:
const { data } = trpc.useQuery(["company.listIds"], {
initialData: []
});
const { data } = trpc.useQuery(["company.listIds"], {
initialData: []
});
Dani;
Dani;OP3y ago
Tried this, while the actual data value at runtime is an array, the type is still
{ id: string }[] | undefined
{ id: string }[] | undefined
julius
julius3y ago
i would think thats cause the initialData is only used for the first fetch? it can become undefined again later? if you also use keepPreviousData it should always be defined i guess 🤔
Dani;
Dani;OP3y ago
Hm that makes sense, this also seems to be the behaviour with react-query Nope, keepPreviousData doesn't change the type
julius
julius3y ago
cc @TkDodo should the undefined be omitted if both keepPreviousData and initialData is provided or is there some other way to do this?
TkDodo 🔮
TkDodo 🔮3y ago
so with plain TanStack/query, you can use destructuring and assign an empty array and the type will be preserved. you can also use initialData, which will narrow the type and remove undefined from the union. However, be aware that this is semantically different. If you have a staleTime set and provide initialData, there won't be a fetch. Because initialData is treated as any other data that is put into the cache directly (like calling setQueryData). You can read about this in this article: https://tkdodo.eu/blog/placeholder-and-initial-data-in-react-query Lastly, you can pass placeholderData, which will give you a fetch in any case because the data is never persisted. But that also means its potentially undefined because it will rollback to undefined for example if there is an error. Here are the three options in a typescript playground: https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAOQACMAhgHaoMDGA1gPRTr2swBaAI458VAFDjWEZvBLoYrABYBJeAF44ACgCUALjgAFciGAYAPAEEoUennONkIAEa4AfG7jrPximfQAdDyoEAA2AG7oWgDaAKwANHAAbIkA7AC6OpLSsigYACL0DACMXto6Xp4I4nBwOSyIcAAmRfRl0elEZWhYongxVOzoeFTpifKKqjBZtZyctQtwAHoA-OKE2TINPYUMAExlupWINXVb8EgtDF2aPdi4-dGDw6PjCspqiUjAjMAwwPRQrt6AYOkQZnA5otaqt1ptcjtWgBmQ4VbwnWr1C7NVo3PK9B4DIYjMakd5TL5wMChPjoJRhJq4YGgzqECFQ6GwwhAA
julius
julius3y ago
Just checked on a v10 example and you can assign a default to the data there too and preserve the type. Seems to work the same in tanstack/query as trpc then which is good
julius
julius3y ago
so will assigning an empty array put it in the cache too or what's the difference between that and using initialData? EDIT: nvm says in the post
julius
julius3y ago
actually the initialData one is different 🤔 may look into that later
TkDodo 🔮
TkDodo 🔮3y ago
We've added overloads in v4 to make initialData narrow the type Those live on useQuery so you'd likely have to duplicate the logic?
julius
julius3y ago
we just use the UseQueryResult type. I see you also have a DefinedUseQueryResult which we could probably use without looking too deep into it https://github.com/TanStack/query/blob/afbd6c73776ad2d68b6d5b64ce9888c85c745a90/packages/react-query/src/useQuery.ts#L24-L34
TkDodo 🔮
TkDodo 🔮3y ago
exactly. DefinedUseQueryResult is the one that is used in the overloads where initialData is passed and doesn't return undefined
Alex / KATT 🐱
Interesting, maybe we need overloads too then