TypeScript

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

需要记住的事情

  • 当前类型需要使用 TypeScript v4.7 或更高版本
  • 此仓库中类型的更改被认为是非破坏性的,通常以 patch semver 更改的形式发布(否则,每次类型增强都将是一个主要版本!)。
  • 强烈建议您将 vue-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 字段添加类型

error 的类型默认为 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 的东西,您可以指定 error 字段的类型

但是,这样做有一个缺点,即 useQuery 的所有其他泛型的类型推断将不再起作用。 通常不认为抛出不是 Error 的东西是一种好的做法,因此,如果您有像 AxiosError 这样的子类,则可以使用类型收窄来使 error 字段更具体

注册全局 Error

TanStack Query v5 允许通过修改 Register 接口,为所有内容设置全局 Error 类型,而无需在调用端指定泛型。 这将确保推断仍然有效,但 error 字段将是指定的类型

为查询和突变键添加类型

注册查询和突变键类型

同样类似于注册全局错误类型,您还可以注册全局 QueryKeyMutationKey 类型。 这允许您为键提供更多结构,以匹配应用程序的层次结构,并在库的所有表面区域中对它们进行类型化。 请注意,注册的类型必须扩展 Array 类型,以便您的键仍然是数组。

ts
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 来禁用查询。 当您想根据条件禁用查询,但仍希望保持查询类型安全时,这很有用。 在禁用查询指南中阅读更多相关信息。