Обработка ошибок в RTK Query
Не могу получить доступ к данным об ошибке в RTK Query. В документации четко показано, что объект ошибки, который достается из генерируемого хука мутации имеет поле data.
На деле же объект имеет юнион тип FetchBaseQueryError | SerializedError | undefined. И при попытке получить доступ к полю data typescript говорит о том, что такого поля не существует.
Пытался даже использовать метод transformErrorResponse внутри функции createApi. Но, при попытке задать свою структуру объекта, возникает множество конфликтов с типизацией, в результате чего изменению поддается только поле status.
api.ts
export const authApi = createApi({
reducerPath: "api/auth",
baseQuery: fetchBaseQuery({ baseUrl: `${process.env.REACT_APP_BASE_URL}/auth` }),
endpoints: (builder) => ({
login: builder.mutation<ResponseBody, RequestBody>({
query: (body) => ({
url: 'login',
method: "POST",
body
})
}),
register: builder.mutation<ResponseBody, RequestBody>({
query: (body) => ({
url: 'registration',
method: "POST",
body,
}),
async onQueryStarted(queryBody, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled
const user = decodeToken(data.token)
dispatch(authorizeUser(user))
} catch (err) {
console.error(err)
}
},
})
})
component.tsx
export const RegistrationBody: React.FC = () => {
// ... //
const [register, { error, isError, data }] = useRegisterMutation()
const submit = async (event: React.MouseEvent) => {
event.preventDefault()
await register({ email, password })
}
// ... //
if (isError && error) console.log(error.data)
return (
// ... //
)
}
В компоненте, при попытке получить доступ к полю data, получаю ошибку
Property 'data' does not exist on type 'FetchBaseQueryError | SerializedError'. Property 'data' does not exist on type 'SerializedError'.
Ответы (1 шт):
Также сталкивался примерно с похожей проблемой.
Здесь вижу два возможных варианты решения:
- При использовании fetchBaseQuery свойство error, возвращаемое из перехватчика, будет иметь тип Ошибка базового запроса FetchBaseQueryError | SerializedError | undefined. Если ошибка присутствует, вы можете получить доступ к свойствам ошибки, сузив тип либо до FetchBaseQueryError, либо до SerializedError.
Собственно сузить тип можно с помощью следующих функций:
services/helpers.ts
import { FetchBaseQueryError } from '@reduxjs/toolkit/query'
export function isFetchBaseQueryError(error: unknown): error is FetchBaseQueryError {
return typeof error === 'object' && error != null && 'status' in error
}
export function isErrorWithMessage(
error: unknown,
): error is { message: string } {
return (
typeof error === 'object' &&
error != null &&
'message' in error &&
typeof (error as any).message === 'string'
)
}
addPost.tsx
import { useState } from 'react'
import { useSnackbar } from 'notistack'
import { api } from './services/api'
import { isFetchBaseQueryError, isErrorWithMessage } from './services/helpers'
function AddPost() {
const { enqueueSnackbar, closeSnackbar } = useSnackbar()
const [name, setName] = useState('')
const [addPost] = useAddPostMutation()
async function handleAddPost() {
try {
await addPost(name).unwrap()
setName('')
} catch (err) {
if (isFetchBaseQueryError(err)) {
// you can access all properties of `FetchBaseQueryError` here
const errMsg = 'error' in err ? err.error : JSON.stringify(err.data)
enqueueSnackbar(errMsg, { variant: 'error' })
} else if (isErrorWithMessage(err)) {
// you can access a string 'message' property here
enqueueSnackbar(err.message, { variant: 'error' })
}
}
}
return (
<div>
<input value={name} onChange={(e) => setName(e.target.value)} />
<button>Add post</button>
</div>
)
}
Весь код взят из документации по RTK Query: https://redux-toolkit.js.org/rtk-query/usage-with-typescript#error-result-example
- Написать свою кастомную ошибку с использованием своей функции для обращения к серверу queryFn, вместо стандартного query. Ссылка на документацию: https://redux-toolkit.js.org/rtk-query/usage-with-typescript#type-safe-error-handling и https://redux-toolkit.js.org/rtk-query/usage-with-typescript#typing-a-queryfn