skipTokenReact Query ist jetzt in TypeScript geschrieben, um sicherzustellen, dass die Bibliothek und Ihre Projekte typsicher sind!
Zu beachtende Punkte
Typen in React Query fließen im Allgemeinen sehr gut durch, sodass Sie keine Typannotationen selbst bereitstellen müssen.
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(),
})
Dies funktioniert am besten, wenn Ihre queryFn einen klar definierten Rückgabetyp hat. Beachten Sie, dass die meisten Datenabrufbibliotheken standardmäßig any zurückgeben, stellen Sie also sicher, dass Sie sie in eine ordnungsgemäß typisierte Funktion extrahieren
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 verwendet einen diskriminierten Union-Typ für das Abfrageergebnis, der durch das Feld status und die abgeleiteten booleschen Statusflags diskriminiert wird. Dies ermöglicht es Ihnen, z. B. den success-Status zu überprüfen, um data zu definieren
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
}
Der Typ für Fehler ist standardmäßig Error, da dies das ist, was die meisten Benutzer erwarten.
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: Error
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: Error
Wenn Sie einen benutzerdefinierten Fehler oder etwas werfen möchten, das kein Error ist, können Sie den Typ des Fehlerfelds angeben
const { error } = useQuery<Group[], string>(['groups'], fetchGroups)
// ^? const error: string | null
const { error } = useQuery<Group[], string>(['groups'], fetchGroups)
// ^? const error: string | null
Dies hat jedoch den Nachteil, dass die Typinferenz für alle anderen Generika von useQuery nicht mehr funktioniert. Es gilt im Allgemeinen nicht als gute Praxis, etwas anderes als einen Error auszulösen. Wenn Sie also eine Unterklasse wie AxiosError haben, können Sie Typ-Narrowing verwenden, um das Fehlerfeld spezifischer zu machen.
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 ermöglicht es, einen globalen Fehlertyp für alles festzulegen, ohne Generika auf der Aufruferseite angeben zu müssen, indem das Register-Interface ergänzt wird. Dies stellt sicher, dass die Inferenz weiterhin funktioniert, aber das Fehlerfeld den angegebenen Typ hat. Wenn Sie erzwingen möchten, dass Aufrufer explizite Typ-Verengung durchführen müssen, setzen Sie defaultError auf unknown
import '@tanstack/react-query'
declare module '@tanstack/react-query' {
interface Register {
// Use unknown so call sites must narrow explicitly.
defaultError: unknown
}
}
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: unknown | null
import '@tanstack/react-query'
declare module '@tanstack/react-query' {
interface Register {
// Use unknown so call sites must narrow explicitly.
defaultError: unknown
}
}
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: unknown | null
Ähnlich wie bei der Registrierung eines globalen Fehlertyps können Sie auch einen globalen Meta-Typ registrieren. Dies stellt sicher, dass das optionale Feld meta für Queries und Mutations konsistent und typsicher bleibt. Beachten Sie, dass der registrierte Typ Record<string, unknown> erweitern muss, damit meta ein Objekt bleibt.
import '@tanstack/react-query'
interface MyMeta extends Record<string, unknown> {
// Your meta type definition.
}
declare module '@tanstack/react-query' {
interface Register {
queryMeta: MyMeta
mutationMeta: MyMeta
}
}
import '@tanstack/react-query'
interface MyMeta extends Record<string, unknown> {
// Your meta type definition.
}
declare module '@tanstack/react-query' {
interface Register {
queryMeta: MyMeta
mutationMeta: MyMeta
}
}
Ebenso wie bei der Registrierung eines globalen Fehlertyps können Sie auch einen globalen QueryKey- und MutationKey-Typ registrieren. Dies ermöglicht es Ihnen, Ihren Schlüsseln mehr Struktur zu geben, die der Hierarchie Ihrer Anwendung entspricht, und sie über die gesamte Oberfläche der Bibliothek typsicher zu machen. Beachten Sie, dass der registrierte Typ von Array erben muss, damit Ihre Schlüssel ein Array bleiben.
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
}
}
Wenn Sie Query-Optionen in useQuery einfügen, erhalten Sie automatische Typinferenz. Möglicherweise möchten Sie die Query-Optionen jedoch in eine separate Funktion extrahieren, um sie zwischen useQuery und z. B. prefetchQuery zu teilen. In diesem Fall würden Sie die Typinferenz verlieren. Um sie wiederherzustellen, können Sie den queryOptions-Helfer verwenden
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())
Darüber hinaus kennt der von queryOptions zurückgegebene queryKey die zugehörige queryFn, und wir können diese Typinformationen nutzen, um Funktionen wie queryClient.getQueryData ebenfalls typsicher zu machen
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
Ohne queryOptions wäre der Typ von data unknown, es sei denn, wir würden ihm ein Generic übergeben
const data = queryClient.getQueryData<Group[]>(['groups'])
const data = queryClient.getQueryData<Group[]>(['groups'])
Ähnlich wie bei queryOptions können Sie mutationOptions verwenden, um Mutationsoptionen in eine separate Funktion zu extrahieren.
function groupMutationOptions() {
return mutationOptions({
mutationKey: ['addGroup'],
mutationFn: addGroup,
})
}
useMutation({
...groupMutationOptions(),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['groups'] }),
})
useIsMutating(groupMutationOptions())
queryClient.isMutating(groupMutationOptions())
function groupMutationOptions() {
return mutationOptions({
mutationKey: ['addGroup'],
mutationFn: addGroup,
})
}
useMutation({
...groupMutationOptions(),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['groups'] }),
})
useIsMutating(groupMutationOptions())
queryClient.isMutating(groupMutationOptions())
Wenn Sie TypeScript verwenden, können Sie skipToken verwenden, um eine Abfrage zu deaktivieren. Dies ist nützlich, wenn Sie eine Abfrage bedingt deaktivieren möchten, aber die Abfrage dennoch typsicher halten möchten. Lesen Sie mehr darüber im Leitfaden Disabling Queries.
Tipps und Tricks zur Typinferenz finden Sie unter React Query und TypeScript in den Community-Ressourcen. Um herauszufinden, wie Sie die bestmögliche Typsicherheit erreichen können, lesen Sie Type-safe React Query. The Query Options API erläutert, wie die Typinferenz mit der queryOptions-Hilfsfunktion funktioniert.