What is the correct way of typechecking a ReactQuery custom fetch ? . I'm getting an error of : "….is of type unknown"

huangapple go评论69阅读模式
英文:

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&lt;IResponse, unknown&gt; | QueryObserverLoadingErrorResult&lt;IResponse, unknown&gt;
&#39;locationQuery.error&#39; is of type &#39;unknown

This is what I have now.


interface IResponse extends IGeolocation { ...some interface data }

export async function getLocation(searchTerm: string): Promise&lt;IResponse&gt; {
  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&lt;IResponse&gt;(
    [&#39;location&#39;, { searchTerm }],
    () =&gt; getLocation(searchTerm),
    {
      enabled: !!searchTerm,
    },
  );
}

and here is how I'm using it


... some omitted code 

const locationQuery = useLocation(searchTerm);

... some omitted code

 &lt;pre&gt;{JSON.stringify(locationQuery.data, null, 2)}&lt;/pre&gt;
 {locationQuery.isError &amp;&amp; &lt;p&gt;{locationQuery.error.message}&lt;/p&gt;} // &lt;&lt;- [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&lt;IResponse, { message: string }&gt;([&quot;location&quot;, { searchTerm }], () =&gt; 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.

Playground

答案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% 的人不会这样做,而且运行时错误也总是一个带有 messageError
  • 如果你有不同的错误类型要指定,你可以全局覆盖所有情况的 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 using select.

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 type Error, not unknown. 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 an Error with a message.
  • 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 &#39;@tanstack/react-query&#39; {
  interface Register {
    defaultError: AxiosError
  }
}

const { error } = useQuery({ queryKey: [&#39;groups&#39;], 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.

huangapple
  • 本文由 发表于 2023年3月3日 18:07:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75625670.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定