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> {
// 您的 meta 型別定義。
}
declare module '@tanstack/react-query' {
interface Register {
queryMeta: MyMeta
mutationMeta: MyMeta
}
}
import '@tanstack/react-query'
interface MyMeta extends Record<string, unknown> {
// 您的 meta 型別定義。
}
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 來停用查詢。這在您想根據條件停用查詢但仍希望保持查詢型別安全時非常有用。更多資訊請參閱停用查詢指南。