框架
版本

TypeScript

Solid Query 使用 TypeScript 编写,以确保库和您的项目都是类型安全的!

需要注意的事项

  • 当前类型要求使用 TypeScript v4.7 或更高版本
  • 此仓库中类型的更改被视为非破坏性更改,通常作为补丁语义版本更改发布(否则每次类型增强都会是主要版本!)
  • 强烈建议您将 solid-query 包的版本锁定到特定的补丁版本,并升级时预期类型可能在任何版本之间修复或升级
  • Solid Query 的非类型相关的公共 API 仍然非常严格地遵循 semver。

类型推断

Solid Query 中的类型通常能够很好地流动,因此您无需自行提供类型注解。

tsx
import { useQuery } from '@tanstack/solid-query'

const query = useQuery(() => ({
  queryKey: ['number'],
  queryFn: () => Promise.resolve(5),
}))

query.data
//    ^? (property) data: number | undefined
import { useQuery } from '@tanstack/solid-query'

const query = useQuery(() => ({
  queryKey: ['number'],
  queryFn: () => Promise.resolve(5),
}))

query.data
//    ^? (property) data: number | undefined

TypeScript Playground

tsx
import { useQuery } from '@tanstack/solid-query'

const query = useQuery(() => ({
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
  select: (data) => data.toString(),
}))

query.data
//    ^? (property) data: string | undefined
import { useQuery } from '@tanstack/solid-query'

const query = useQuery(() => ({
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
  select: (data) => data.toString(),
}))

query.data
//    ^? (property) data: string | undefined

TypeScript Playground

当您的 queryFn 返回类型定义明确时,效果最佳。请记住,大多数数据获取库默认返回 any,因此请确保将其提取到类型正确的函数中。

tsx
const fetchGroups = (): Promise<Group[]> =>
  axios.get('/groups').then((response) => response.data)

const query = useQuery(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.data
//    ^? (property) data: Group[] | undefined
const fetchGroups = (): Promise<Group[]> =>
  axios.get('/groups').then((response) => response.data)

const query = useQuery(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.data
//    ^? (property) data: Group[] | undefined

TypeScript Playground

类型缩小

Solid Query 使用 鉴别联合类型 来表示查询结果,该类型由 status 字段和派生的状态布尔标志来鉴别。这将允许您检查例如 success 状态,从而使 data 被定义。

tsx
const query = useQuery(() => ({
  queryKey: ['number'],
  queryFn: () => Promise.resolve(5),
}))

if (query.isSuccess) {
  const data = query.data
  //     ^? const data: number
}
const query = useQuery(() => ({
  queryKey: ['number'],
  queryFn: () => Promise.resolve(5),
}))

if (query.isSuccess) {
  const data = query.data
  //     ^? const data: number
}

TypeScript Playground

错误字段的类型定义

error 的类型默认为 Error,因为这是大多数用户所期望的。

tsx
const query = useQuery(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.error
//    ^? (property) error: Error | null
const query = useQuery(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.error
//    ^? (property) error: Error | null

TypeScript Playground

如果您想抛出自定义错误,或者根本不是 Error 的东西,您可以指定 error 字段的类型

tsx
const query = useQuery<Group[], string>(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.error
//    ^? (property) error: string | null
const query = useQuery<Group[], string>(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.error
//    ^? (property) error: string | null

然而,这有一个缺点,即 useQuery 所有其他泛型的类型推断将不再起作用。抛出非 Error 的东西通常不被认为是好的做法,所以如果您有一个像 AxiosError 这样的子类,您可以使用类型缩小来使错误字段更具体。

tsx
import axios from 'axios'

const query = useQuery(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.error
//    ^? (property) error: Error | null

if (axios.isAxiosError(query.error)) {
  query.error
  //    ^? (property) error: AxiosError
}
import axios from 'axios'

const query = useQuery(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.error
//    ^? (property) error: Error | null

if (axios.isAxiosError(query.error)) {
  query.error
  //    ^? (property) error: AxiosError
}

TypeScript Playground

tsx
import '@tanstack/solid-query'

declare module '@tanstack/solid-query' {
  interface Register {
    // Use unknown so call sites must narrow explicitly.
    defaultError: unknown
  }
}

const query = useQuery(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.error
//    ^? (property) error: unknown | null
import '@tanstack/solid-query'

declare module '@tanstack/solid-query' {
  interface Register {
    // Use unknown so call sites must narrow explicitly.
    defaultError: unknown
  }
}

const query = useQuery(() => ({
  queryKey: ['groups'],
  queryFn: fetchGroups,
}))

query.error
//    ^? (property) error: unknown | null

注册全局 Meta

与注册 全局错误类型 类似,您也可以注册全局 Meta 类型。这确保了 查询突变 上的可选 meta 字段保持一致并且类型安全。请注意,注册的类型必须扩展 Record<string, unknown>,以便 meta 保持为一个对象。

ts
import '@tanstack/solid-query'

interface MyMeta extends Record<string, unknown> {
  // Your meta type definition.
}

declare module '@tanstack/solid-query' {
  interface Register {
    queryMeta: MyMeta
    mutationMeta: MyMeta
  }
}
import '@tanstack/solid-query'

interface MyMeta extends Record<string, unknown> {
  // Your meta type definition.
}

declare module '@tanstack/solid-query' {
  interface Register {
    queryMeta: MyMeta
    mutationMeta: MyMeta
  }
}

查询选项的类型定义

如果您将查询选项内联到 useQuery 中,您将获得自动类型推断。但是,您可能希望将查询选项提取到一个单独的函数中,以便在 useQuery 和例如 prefetchQuery 之间共享它们。在这种情况下,您将失去类型推断。要恢复它,您可以使用 queryOptions 辅助函数。

ts
import { queryOptions } from '@tanstack/solid-query'

function groupOptions() {
  return queryOptions({
    queryKey: ['groups'],
    queryFn: fetchGroups,
    staleTime: 5 * 1000,
  })
}

useQuery(groupOptions)
queryClient.prefetchQuery(groupOptions())
import { queryOptions } from '@tanstack/solid-query'

function groupOptions() {
  return queryOptions({
    queryKey: ['groups'],
    queryFn: fetchGroups,
    staleTime: 5 * 1000,
  })
}

useQuery(groupOptions)
queryClient.prefetchQuery(groupOptions())

此外,从 queryOptions 返回的 queryKey 知道与之关联的 queryFn,我们可以利用这些类型信息使诸如 queryClient.getQueryData 之类的函数也了解这些类型。

ts
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

没有 queryOptionsdata 的类型将是 unknown,除非我们为它传递一个泛型。

ts
const data = queryClient.getQueryData<Group[]>(['groups'])
const data = queryClient.getQueryData<Group[]>(['groups'])

使用 skipToken 类型安全地禁用查询

如果您正在使用 TypeScript,您可以使用 skipToken 来禁用查询。当您想基于某个条件禁用查询,但又想保持查询的类型安全时,这很有用。

禁用查询 指南中可以阅读更多关于此内容。