react-query手把手教程21-typescript

951 阅读4分钟

场景

在目前的前端社区中,已经有越来越多的人使用typescript来编写项目。在这里笔者就不单独介绍typescript的优点及使用了,掘金上有一堆的文章,你可以自行去搜索相关的教程。

本篇文章主要讲述如何在react-query中使用typescript。

实践

对查询函数返回值定义类型

最简单的使用方法是,在传入的查询函数中,标记返回数据的数据类型,这样最后读取data属性值也是该数据类型。

interface Issue {
  id:number;
  title:string;
  number:number;
  body:string;
  state: "open" | "closed";
}

const Issues = ({org, repo}:{org:string, repo:string}) => {
  const issuesQuery = useQuery(
    ["issues", org, repo],
    async () => {
      const response = await fetch(
        `https://api.github.com/repos/${org}/${repo}/issues`
      )
      // ①
      const json: Issue[] = await response.json()
      return json;
    }
  )

  console.log(issuesQuery.data) // Issue[] | undefined
  // ...
}

①:在这里将后端返回的数据json定义为Issue[]类型,此时你再获取数据时,Issues.data的数据类型也是相同的。

在这里需要注意的是,Issues.data的数据类型不止是Issue[]类型,它同样也具有undefined类型,因为在第一次获取数据时,Issues.data默认为undefined

那么react-query是怎么推断出数据属性类型的呢?

react-query会使用一个泛型并自动推断其类型作为查询函数的返回类型。如果你想验证查询函数是否返回正确的类型,可以将一个类型作为第一个泛型参数传递给useQuery。如果类型不匹配,TypeScript会返回一个警告。

const issuesQuery = useQuery<Issue[]>(
  ["issues", org, repo],
  // Type Error: Type 'string[]' is not assignable to type 'Issue[]'
  async () => {
    const response = await fetch(
      `https://api.github.com/repos/${org}/${repo}/issues`
    )
    const json: string[] = await response.json()
    return json;
  }
)

对抛出的错误定义类型

快速回顾一下在日常开发中TypeScript如何正常处理错误。

当你在JavaScript中抛出任何东西时,你可以使用try{} catch{}在任何地方捕获该错误。错误作为参数传递给catch,类似于下面的代码:

try {
  throw new Error("Something went wrong")
} catch (error) {}

如果你正在调用许多三方库或者其它的一些函数方法,TypeScript🈶可能无法推断出错误的类型。因此这个error隐含了any类型,这将导致typescript失去用武之地。因此从TypeScript 4.4开始,任何被获取的error都是unknown类型,所以可以使用instanceof操作符来查看是否是一个错误。示例代码如下:

try {
  throw new Error("Something went wrong")
} catch (error) {
  if (error instanceof Error) {
    console.error(error.message)
  }
}

那么在react-query中该如何处理错误呢?答案是你只需要在useQuery的第二个泛型中传入错误的类型即可,类似于下面的代码:

const issuesQuery = useQuery<Issue[], Error>(
  ["issues", org, repo],
  async () => {
    const response = await fetch(
      `https://api.github.com/repos/${org}/${repo}/issues`
    )
    const json: Issue[] = await response.json()
    return json;
  }
)

console.log(issuesQuery.error) // Error | undefined

Error类型可以随意自定义,如果不传入定义的错误类型,此时默认的类型就是上文所述的unknown

使用select配置项的数据类型定义

还记得在react-query手把手教程19-渲染优化这篇文章中介绍的select配置项么?它可以很好的对我们的数据进行转换。但是也会造成一个问题,如何对转换后的数据进行类型定义,此时你就需要用到useQuery钩子的第三个泛型:

const issuesQuery = useQuery<Issue[], Error, string[]>(
  ["issues", org, repo],
  async () => {
    const response = await fetch(
      `https://api.github.com/repos/${org}/${repo}/issues`
    )
    const json: string[] = await response.json()
    return json;
  },
  {
    select: (data: Issue[]) => data.map(issue => issue.title)
  }
)

在这里我们需要回顾一下,第一个泛型是查询函数返回的数据是否符合定义,第二个泛型是定义错误的数据类型,第三个泛型是通过select配置项处理后,实际你获得的issuesQuery.data的类型(如果没有select配置项,那么第一个泛型就是最后issuesQuery.data的类型)。

对查询键进行类型定义

在多数情况下,查询键的默认定义是readonly unknown[]这样可以覆盖所有传入的查询键类型。

在react-query中,你可以将传入的查询键,用as const设置为元组,让typescript自己检测出类型即可,类似于下面的代码:

const [pageNum, setPageNum] = useState(1);

const issuesQuery = useQuery(
  ["issues", org, repo, {page: pageNum}] as const,
  async ({queryKey}) => {
    // parameter queryKey: 
    // readonly ["issues", string, string, {page :number}]
    // ... 
  }
)

到这里对于react-query与typescript的结合使用就结束了,已经可以覆盖你大多数的使用场景了,如果需要学习更多,可以去官网深入学习。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 29 天,点击查看活动详情