Code:
export const useAllUsers = <T extends UserResponseDto>(
select?: (data: UserResponseDto[]) => T
) =>
useQuery<UserResponseDto[], ErrorResponse, T, string[]>({
queryKey: [QueryClientKeys.GET_ALL_USERS],
queryFn: async () => {
const response = await ApiService.getAllUsers();
return response.data;
},
select: select,
staleTime: Infinity,
cacheTime: Infinity,
retry: false,
});
Is it possible to define the selector for a useQuery hook to return a generic type as above?
With this setup, whenever I use the useAllUsers
hook without passing the select
function, I get UserResponseDto
as the data
type and not UserResponseDto[]
.
2
Answers
You are telling
useQuery
that the data type returned from it is of typeT extends UserResponseDto
, so in no case could that beUserResponseDto[]
sinceUserResponseDto[]
does not extendUserResponseDto
.Do you really mean
<T extends UserResponseDto>
? Because<T extends UserResponseDto[]>
makes more sense to me and would solve the issue.If
<T extends UserResponseDto>
is what you want you could do<T extends unknown = UserResponseDto[]>
, to allowselect
to return any type, but in the same time tell the compiler that ifselect
doesn’t exist, the data type isUserResponseDto[]
.your generic is defined as:
T extends UserResponseDto
However,
select
can return anything – it shouldn’t be bound to be something that is "assignable to"UserResponseDto
. But what you’d want to express is thatT
should default toUserResponseDto[]
for cases where you don’t provide aselect
function, becauseselect
is whereuseQuery
infers the type ofT
from.That means you need:
T = UserResponseDto[]
instead.