TypeScript

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

需要注意的事项

  • 当前类型要求使用 TypeScript v4.7 或更高版本
  • 此仓库中类型的更改被视为非破坏性更改,通常作为补丁语义版本更改发布(否则每次类型增强都会是主要版本!)
  • 强烈建议您将 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,因为这是大多数用户所期望的。

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,您可以使用类型缩小来使错误字段更具体。

注册全局错误类型

TanStack Query v5 允许通过修改 Register 接口来为所有内容设置全局错误类型,而无需在调用端指定泛型。这将确保推断仍然有效,但错误字段将是指定类型。如果您想强制调用端进行显式类型缩小,请将 defaultError 设置为 unknown

tsx
import '@tanstack/vue-query'

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

const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const error: unknown | null
import '@tanstack/vue-query'

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

const { error } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups })
//      ^? const error: unknown | null

键入查询和变异键

注册查询和变异键类型

与注册 全局错误类型 类似,您还可以注册全局 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 来禁用查询。当您想根据条件禁用查询,但仍希望保持查询的类型安全时,这非常有用。在 禁用查询 指南中阅读更多相关信息。