TypeScript

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

需要注意的事项:

  • 类型目前需要使用 TypeScript v4.7 或更高版本
  • 此存储库中类型的更改被视为非重大更改,通常作为 补丁 semver 更改发布(否则每次类型增强都将是一个主要版本!)。
  • 强烈建议您将 react-query 包版本锁定到特定的补丁版本,并在升级时预期类型在任何版本之间都可能被修复或升级
  • Vue Query 的非类型相关公共 API 仍然严格遵循 semver。

类型推断

Vue Query 中的类型通常可以很好地传递,因此您不必自己提供类型注释

tsx
const { data } = useQuery({
  //    ^? const data: Ref<number> | Ref<undefined>
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
})
const { data } = useQuery({
  //    ^? const data: Ref<number> | Ref<undefined>
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
})

typescript playground

tsx
const { data } = useQuery({
  //      ^? const data: Ref<string> | Ref<undefined>
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
  select: (data) => data.toString(),
})
const { data } = useQuery({
  //      ^? const data: Ref<string> | Ref<undefined>
  queryKey: ['test'],
  queryFn: () => Promise.resolve(5),
  select: (data) => data.toString(),
})

typescript playground

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

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

const { data } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const data: Ref<Group[]> | Ref<undefined>
const fetchGroups = (): Promise<Group[]> =>
  axios.get('/groups').then((response) => response.data)

const { data } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const data: Ref<Group[]> | Ref<undefined>

typescript playground

类型收窄

Vue Query 对查询结果使用可区分联合类型,由 status 字段和派生的状态布尔标志进行区分。这将允许您检查例如 success 状态以使 data 定义:

tsx
const { data, isSuccess } = reactive(
  useQuery({
    queryKey: ['test'],
    queryFn: () => Promise.resolve(5),
  }),
)

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

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

typescript playground

键入错误字段

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

tsx
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const error: Ref<unknown>

if (error.value instanceof Error) {
  error.value
  //     ^? const error: Error
}
const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const error: Ref<unknown>

if (error.value instanceof Error) {
  error.value
  //     ^? const error: Error
}

typescript playground

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

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

注册全局错误

TanStack Query v5 提供了一种为所有内容设置全局错误类型的方法,而无需在调用端指定泛型,方法是修改 Register 接口。这将确保推断仍然有效,但错误字段将是指定的类型:

键入查询和变更键

注册查询和变更键类型

同样,与注册全局错误类型类似,您也可以注册全局 QueryKeyMutationKey 类型。这允许您为您的键提供更符合应用程序层次结构的结构,并在库的所有表面区域对它们进行类型化。请注意,注册的类型必须扩展 Array 类型,以便您的键保持为数组。

tsx
import '@tanstack/vue-query'

type QueryKey = ['dashboard' | 'marketing', ...ReadonlyArray<unknown>]

declare module '@tanstack/vue-query' {
  interface Register {
    queryKey: QueryKey
    mutationKey: QueryKey
  }
}
import '@tanstack/vue-query'

type QueryKey = ['dashboard' | 'marketing', ...ReadonlyArray<unknown>]

declare module '@tanstack/vue-query' {
  interface Register {
    queryKey: QueryKey
    mutationKey: QueryKey
  }
}

使用 skipToken 对查询进行类型安全的禁用

如果您正在使用 TypeScript,则可以使用 skipToken 来禁用查询。当您想根据条件禁用查询,但仍希望保持查询类型安全时,这很有用。 在禁用查询指南中阅读更多相关信息。