英文:
What is the correct way of typechecking a ReactQuery custom fetch ? . I'm getting an error of : "....is of type unknown"
问题
Sure, here are the translated code parts:
我正在使用 `typescript + react-query`,并编写自定义的 fetch。我想正确地为这个 `function` 添加类型,但在尝试使用 `myQuery.error.message` 时,我遇到了以下 TypeScript 错误。
```ts
const locationQuery: QueryObserverRefetchErrorResult<IResponse, unknown> | QueryObserverLoadingErrorResult<IResponse, unknown>
'locationQuery.error' 是类型 'unknown'
这是我现在拥有的代码。
interface IResponse extends IGeolocation { ...一些接口数据 }
export async function getLocation(searchTerm: string): Promise<IResponse> {
console.log(`searchTerm binnen getLocation: ${searchTerm}`);
const result = await geopuntApi.get(`/geolocation/location?q=${searchTerm}`);
console.log(`result: ${result}`);
return result.data.LocationResult;
}
export function useLocation(searchTerm: string) {
console.log(`searchTerm binnen useLocation: ${searchTerm}`);
return useQuery<IResponse>(
['location', { searchTerm }],
() => getLocation(searchTerm),
{
enabled: !!searchTerm,
},
);
}
这是我如何使用它的方式。
... 一些省略的代码
const locationQuery = useLocation(searchTerm);
... 一些省略的代码
<pre>{JSON.stringify(locationQuery.data, null, 2)}</pre>
{locationQuery.isError && <p>{locationQuery.error.message}</p>} // <<-[错误] 在这里
希望这对您有帮助。
英文:
I'm using typescript + react-query
and I'm writing a custom fetch. I want to properly type this function
, but I'm getting confused on how best to do it and I'm getting the following typescript error when trying to use the myQuery.error.message
const locationQuery: QueryObserverRefetchErrorResult<IResponse, unknown> | QueryObserverLoadingErrorResult<IResponse, unknown>
'locationQuery.error' is of type 'unknown
This is what I have now.
interface IResponse extends IGeolocation { ...some interface data }
export async function getLocation(searchTerm: string): Promise<IResponse> {
console.log(`searchTerm binnen getLocation: ${searchTerm}`);
const result = await geopuntApi.get(`/geolocation/location?q=${searchTerm}`);
console.log(`result: ${result}`);
return result.data.LocationResult;
}
export function useLocation(searchTerm: string) {
console.log(`searchTerm binnen useLocation: ${searchTerm}`);
return useQuery<IResponse>(
['location', { searchTerm }],
() => getLocation(searchTerm),
{
enabled: !!searchTerm,
},
);
}
and here is how I'm using it
... some omitted code
const locationQuery = useLocation(searchTerm);
... some omitted code
<pre>{JSON.stringify(locationQuery.data, null, 2)}</pre>
{locationQuery.isError && <p>{locationQuery.error.message}</p>} // <<- [ERROR] here
答案1
得分: 1
你缺少了查询可能生成的错误类型的通用参数:
export function useLocation(searchTerm: string) {
console.log(`searchTerm binnen useLocation: ${searchTerm}`);
return useQuery<IResponse, { message: string }>(["location", { searchTerm }], () => getLocation(searchTerm), {
enabled: !!searchTerm,
});
}
在这里,我只是添加了 { message: string }
,只是为了满足编译器,以便当你尝试使用 locationQuery.error.message
时不会出错,但你可能稍后想找到正确的类型。
英文:
You're missing the generic parameter for the type of the errors the query can generate:
export function useLocation(searchTerm: string) {
console.log(`searchTerm binnen useLocation: ${searchTerm}`);
return useQuery<IResponse, { message: string }>(["location", { searchTerm }], () => getLocation(searchTerm), {
enabled: !!searchTerm,
});
}
Here I've just added { message: string }
just to satisfy the compiler for when you try to use locationQuery.error.message
, but you may want to find the correct type later.
答案2
得分: 1
没有一种方式可以“正确类型化”错误,因为不能保证会引发某种特定类型的错误。使用 Promises 时,只能为成功的 Promise 的值进行类型标注。对于错误部分,类型要么是 undefined
要么是 any
。
这与使用 try / catch
相同 - 在 catch
部分捕获到的错误类型要么是 unknown
要么是 any
- 取决于你的 TypeScript 设置。
虽然有方法可以“类型化”它,但我们所做的一切都是对编译器的“伪装”:
- 像 这个答案 建议的传递泛型是可能的,但会引发一组不同的问题。
useQuery
有 4 个泛型参数,如果你只提供了两个,另外两个将回退到默认值,这将导致在某些情况下类型推断无法正常工作,尤其当你使用select
时。
所以,真正你能做的最好的事情只是在运行时进行类型缩小:
const { error } = useQuery(...)
if (error instanceof Error) {
// error.message 现在是字符串类型
}
我在这个主题上有一篇博客文章:https://tkdodo.eu/blog/react-query-and-type-script#what-about-error
在 React Query 的 v5 版本(目前处于 alpha 阶段),我们进行了以下方便的改进:
- 默认情况下,
Errors
的类型将是Error
,而不是unknown
。这将使.message
默认可用。严格来说,这并不“正确”,因为你仍然可以使用非错误值来拒绝一个 Promise,但99% 的人不会这样做,而且运行时错误也总是一个带有message
的Error
。 - 如果你有不同的错误类型要指定,你可以全局覆盖所有情况的 Error 类型。当然,这更加“不安全”,但如果你确定始终会得到一个
AxiosError
,你可以这样做:
declare module '@tanstack/react-query' {
interface Register {
defaultError: AxiosError
}
}
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: AxiosError | null
这个示例来自于 v5 文档:https://tanstack.com/query/v5/docs/react/typescript#registering-a-global-error
当然,如果需要的话,你也可以将错误类型重新设定为 unknown
。
1: https://www.typescriptlang.org/tsconfig/#useUnknownInCatchVariables
2: https://stackoverflow.com/a/75629635/8405310
英文:
There is no way to "properly type" errors, because it's not guaranteed that a certain kind of error is thrown. With Promises, you can only type the value of a successful promise. The one for the erroneous part is either undefined
or any
.
It's the same as with try / catch
- the error you're getting in the catch
part is either unknown
or any
- depending on your TypeScript settings.
There are ways to "type" it, but everything we do is a "lie" to the compiler:
- Passing generics like this answer suggests is possible, but has a different set of issues.
useQuery
has 4 generics, so if you only provide two, the other two fall back to the default value, which will make type inference not work in some situation, especially when you're usingselect
.
So really, the best thing you can do is just a runtime narrowing:
const { error } = useQuery(...)
if (error instanceof Error) {
// error.message is now string
}
I have a blogpost on this topic: https://tkdodo.eu/blog/react-query-and-type-script#what-about-error
In v5 of react-query (currently in alpha), we've made the following convenience improvements:
- per default,
Errors
will be of typeError
, notunknown
. This will make.message
available per default. It's not "correct", strictly speaking, because you could still reject a Promise with a non-error, but 99% of people don't do that, and runtime errors will also always be anError
with amessage
. - you can globally override what your Error type will be for all cases if you have different Error types that you want to specify. Of course, this is even more "unsafe", but if you're sure you're always getting an
AxiosError
, you can do:
declare module '@tanstack/react-query' {
interface Register {
defaultError: AxiosError
}
}
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
// ^? const error: AxiosError | null
This example is from the v5 docs: https://tanstack.com/query/v5/docs/react/typescript#registering-a-global-error
Of course, you can also use this to take errors back to unknown
if you want.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论