Framework
Version

TypeScript

React Query is now written in TypeScript to make sure the library and your projects are type-safe!

Things to keep in mind:

  • Types currently require using TypeScript v4.1 or greater
  • Changes to types in this repository are considered non-breaking and are usually released as patch semver changes (otherwise every type enhancement would be a major version!).
  • It is highly recommended that you lock your react-query package version to a specific patch release and upgrade with the expectation that types may be fixed or upgraded between any release
  • The non-type-related public API of React Query still follows semver very strictly.

Type Inference

Types in React Query generally flow through very well so that you don't have to provide type annotations for yourself

tsx
const { data } = useQuery({
  //    ^? const data: number | undefined
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
})
const { data } = useQuery({
  //    ^? const data: number | undefined
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
})

typescript playground

tsx
const { data } = useQuery({
  //      ^? const data: string | undefined
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
  select: (data) => data.toString(),
})
const { data } = useQuery({
  //      ^? const data: string | undefined
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
  select: (data) => data.toString(),
})

typescript playground

This works best if your queryFn has a well-defined returned type. Keep in mind that most data fetching libraries return any per default, so make sure to extract it to a properly typed function:

tsx
const fetchGroups = (): Promise<Group[]> =>
  axios.get('/groups').then((response) => response.data)

const { data } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const data: Group[] | undefined
const fetchGroups = (): Promise<Group[]> =>
  axios.get('/groups').then((response) => response.data)

const { data } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const data: Group[] | undefined

typescript playground

Type Narrowing

React Query uses a discriminated union type for the query result, discriminated by the status field and the derived status boolean flags. This will allow you to check for e.g. success status to make data defined:

tsx
const { data, isSuccess } = useQuery({
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
})

if (isSuccess) {
  data
  //  ^? const data: number
}
const { data, isSuccess } = useQuery({
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
})

if (isSuccess) {
  data
  //  ^? const data: number
}

typescript playground

Typing the error field

The type for error defaults to unknown. This is in line with what TypeScript gives you per default in a catch clauses (see useUnknownInCatchVariables). The safest way to work with error would be to perform a runtime check; another way would be to explicitly define types for data and error:

tsx
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const error: unknown

if (error instanceof Error) {
  error
  // ^? const error: Error
}
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const error: unknown

if (error instanceof Error) {
  error
  // ^? const error: Error
}

typescript playground

tsx
const { error } = useQuery<Group[], Error>(['groups'], fetchGroups)
//      ^? const error: Error | null
const { error } = useQuery<Group[], Error>(['groups'], fetchGroups)
//      ^? const error: Error | null

typescript playground

Further Reading

For tips and tricks around type inference, have a look at React Query and TypeScript from the Community Resources. To find out how to get the best possible type-safety, you can read Type-safe React Query.