React Query 现已采用 TypeScript 编写,确保库与您的项目具备类型安全!
注意事项:
React Query 中的类型通常能很好地流动,因此您通常无需自行添加类型注解
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),
})
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(),
})
当您的 queryFn 具有明确定义的返回类型时,类型推断效果最佳。请注意大多数数据获取库默认返回 any 类型,因此请确保将其提取到具有正确类型的函数中:
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
React Query 使用 可辨识联合类型 (discriminated union type) 作为查询结果,通过 status 字段和派生的状态布尔标志进行区分。这使您能够检查例如 success 状态来确保 data 已定义:
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
}
错误类型默认为 Error,因为这符合大多数用户的预期。
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: Error
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: Error
如果您想抛出自定义错误,或非 Error 类型的对象,可以指定错误字段的类型:
const { error } = useQuery<Group[], string>(['groups'], fetchGroups)
// ^? const error: string | null
const { error } = useQuery<Group[], string>(['groups'], fetchGroups)
// ^? const error: string | null
但这样做的缺点是 useQuery 的其他泛型参数将无法进行类型推断。通常不建议抛出非 Error 类型的对象,因此如果存在子类如 AxiosError,可以使用类型收窄使错误字段更具体:
import axios from 'axios'
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: Error | null
if (axios.isAxiosError(error)) {
error
// ^? const error: AxiosError
}
import axios from 'axios'
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: Error | null
if (axios.isAxiosError(error)) {
error
// ^? const error: AxiosError
}
TanStack Query v5 允许通过扩展 Register 接口来设置全局错误类型,无需在调用处指定泛型参数。这将确保类型推断仍然有效,同时错误字段会是指定的类型:
import '@tanstack/react-query'
declare module '@tanstack/react-query' {
interface Register {
defaultError: AxiosError
}
}
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: AxiosError | null
import '@tanstack/react-query'
declare module '@tanstack/react-query' {
interface Register {
defaultError: AxiosError
}
}
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: AxiosError | null
与注册 全局错误类型 类似,您也可以注册全局 Meta 类型。这确保 查询 和 变更 中的可选 meta 字段保持一致且类型安全。注意注册的类型必须扩展 Record<string, unknown>,以保证 meta 始终是对象类型。
import '@tanstack/react-query'
interface MyMeta extends Record<string, unknown> {
// 您的元数据类型定义
}
declare module '@tanstack/react-query' {
interface Register {
queryMeta: MyMeta
mutationMeta: MyMeta
}
}
import '@tanstack/react-query'
interface MyMeta extends Record<string, unknown> {
// 您的元数据类型定义
}
declare module '@tanstack/react-query' {
interface Register {
queryMeta: MyMeta
mutationMeta: MyMeta
}
}
同样类似于注册 全局错误类型,您还可以注册全局 QueryKey 和 MutationKey 类型。这允许您为键提供更多结构,匹配应用程序的层次关系,并在库的所有相关接口中保持类型安全。注意注册的类型必须扩展 Array 类型,以确保键仍然是数组形式。
import '@tanstack/react-query'
type QueryKey = ['dashboard' | 'marketing', ...ReadonlyArray<unknown>]
declare module '@tanstack/react-query' {
interface Register {
queryKey: QueryKey
mutationKey: QueryKey
}
}
import '@tanstack/react-query'
type QueryKey = ['dashboard' | 'marketing', ...ReadonlyArray<unknown>]
declare module '@tanstack/react-query' {
interface Register {
queryKey: QueryKey
mutationKey: QueryKey
}
}
如果将查询选项内联到 useQuery 中,您将获得自动类型推断。但若需要将查询选项提取到单独函数中以便在 useQuery 和 prefetchQuery 等场景共享,则会失去类型推断。此时可以使用 queryOptions 辅助函数恢复类型推断:
import { queryOptions } from '@tanstack/react-query'
function groupOptions() {
return queryOptions({
queryKey: ['groups'],
queryFn: fetchGroups,
staleTime: 5 * 1000,
})
}
useQuery(groupOptions())
queryClient.prefetchQuery(groupOptions())
import { queryOptions } from '@tanstack/react-query'
function groupOptions() {
return queryOptions({
queryKey: ['groups'],
queryFn: fetchGroups,
staleTime: 5 * 1000,
})
}
useQuery(groupOptions())
queryClient.prefetchQuery(groupOptions())
此外,queryOptions 返回的 queryKey 知晓关联的 queryFn,我们可以利用此类型信息使 queryClient.getQueryData 等函数也能感知这些类型:
function groupOptions() {
return queryOptions({
queryKey: ['groups'],
queryFn: fetchGroups,
staleTime: 5 * 1000,
})
}
const data = queryClient.getQueryData(groupOptions().queryKey)
// ^? const data: Group[] | undefined
function groupOptions() {
return queryOptions({
queryKey: ['groups'],
queryFn: fetchGroups,
staleTime: 5 * 1000,
})
}
const data = queryClient.getQueryData(groupOptions().queryKey)
// ^? const data: Group[] | undefined
若不使用 queryOptions,data 的类型将为 unknown,除非显式传递泛型参数:
const data = queryClient.getQueryData<Group[]>(['groups'])
const data = queryClient.getQueryData<Group[]>(['groups'])
关于类型推断的技巧,请参阅社区资源中的 React Query 与 TypeScript。要了解如何实现最佳类型安全,可阅读 类型安全的 React Query。
如果使用 TypeScript,可以通过 skipToken 禁用查询。这在需要根据条件禁用查询但仍希望保持类型安全时非常有用。更多信息请参阅 禁用查询 指南。