3

What would be the type which I have defined as any? I have tried TQueryFnData as per the RQ docs. but get Cannot find name 'TQueryFnData'

export const useFetchUser = (userID: string | undefined) => {
    return useQuery<any, Error>([users.fetchUser, userID],
        () => axios.get(`https://jsonplaceholder.typicode.com/users/${userID}`)
            .then(response => response.data))
}

An example of the data returned is: https://jsonplaceholder.typicode.com/users/1

export interface Users {
    id: number,
    name: string,
    username: string,
    email: string,
    address: Address,
    phone: string,
    website: string,
    company: Company
}

export interface Address {
  ...
}

export interface Geo {
  ...
}

export interface Company {
  ...
}
0

3 Answers 3

10

As described in the docs and in my blog, the best thing you can do is make sure that your query function is typed to return a Promise of the type you'd expect. Then, you don't need to pass generics to useQuery at all.

There are many ways to achieve that:

  1. declare return type on the queryFn:
export const useFetchUser = (userID: string | undefined) => {
    return useQuery([users.fetchUser, userID],
        (): Promise<User> => axios.get(`https://jsonplaceholder.typicode.com/users/${userID}`)
            .then(response => response.data))
}
  1. declare a generic for axios.get:
export const useFetchUser = (userID: string | undefined) => {
    return useQuery([users.fetchUser, userID],
        () => axios.get<User>(`https://jsonplaceholder.typicode.com/users/${userID}`)
            .then(response => response.data))
}
Sign up to request clarification or add additional context in comments.

5 Comments

"Then, you don't need to pass generics to useQuery at all" - How do you type the data that is returned from the API on error? Say you leave axios with it's default config so it throws on non-2xx status codes - this propagates into the DefinedUseQueryResult.error field. If I understand correctly, this type cannot be inferred, we have to specify the second generic type param when calling useQuery to specify this type. Which means we need to also specify the first generic type param which is the data the query function expects to be passed in.
On re-reading your answer, I see you probably just mean "you" (as in OP) doesnt need to pass in generics, specifically in the example they provided, and not "you" as in devs in general.
errors are generally not typable because of how javascript and typescript promises work. There is no “error channel” with known, thrown errors. If you have a try/catch, the error will also be of type unknown. That said, since v5 we allow global module augmentation to change the error default type: tanstack.com/query/v5/docs/framework/react/…
I'm not sure I follow what you mean by errors not being typable. This example demonstrates typing the error? Or do you mean that there's no guarantee that the caught error will be of the type specified via the generic type parameter? Thanks for sharing the global error link - very good to know!
yes, this is not “type safe”, it’s a “type assertion” - as if you did error as MyError. There’s nothing safe about that. callApi could reject with something that isn’t of type MyError.
3

Fix typo -

export interface Users
// to
export interface User

It is useQuery<Users, Error>

export const useFetchUser = (userID: string | undefined) => {
    return useQuery<User, Error>([users.fetchUser, userID],
        () => axios.get(`https://jsonplaceholder.typicode.com/users/${userID}`)
            .then(response => response.data))
}

Lastly here's a working example of your code on codesandbox

1 Comment

"It is useQuery<Users, Error>" - Is this a typo? You changed the interface from Users to User - are you still referencing the old name here?
0

As the docs suggest, typing the fetcher function is the best way.

But for use-cases where you use a common fetcher function, Type Generics would be the go to way.

type ApiResponse<T> = {
  data: T;
  // You might want to include other properties like status, message, etc.
};

export const fetcher = async <T>({ queryKey: [url] }: QueryFunctionContext) => {
  if (typeof url === 'string') {
    return axiosInstance.get<ApiResponse<T>>(url).then((res) => res.data.data);
  }

  throw new Error('Invalid url provided');
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.