首页
/ TanStack Query for Angular:CreateQueryOptions 查询选项接口深度解析

TanStack Query for Angular:CreateQueryOptions 查询选项接口深度解析

2026-09-07 16:11:49作者:宗隆裙

本文以 docs/framework/angular/reference/interfaces/CreateQueryOptions.md 参考文档为主体,结合 @tanstack/angular-query-experimental@tanstack/query-core 的源码实现,讲清 CreateQueryOptions 这一 Angular Query 核心查询选项接口的类型继承链、泛型参数含义、全部可用配置项及默认值,以及它在 injectQueryqueryOptions 等实际 API 中的消费方式。读完本文,你可以准确理解该接口为何移除 suspense 选项、如何编写类型安全的查询选项,并掌握各配置项的语义与默认行为。

一、CreateQueryOptions 的定位与定义位置

CreateQueryOptions 是 Angular Query(包名 @tanstack/angular-query-experimental)中描述“一个可创建(create)查询全部配置项”的类型接口。参考文档明确给出其定义位置与继承关系:

Defined in: packages/angular-query-experimental/src/types.ts:35 Extends: OmitKeyof<CreateBaseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>, "suspense">

在源码中可以逐字印证这一点,types.ts 第 35–43 行即:

export interface CreateQueryOptions<
  TQueryFnData = unknown,
  TError = DefaultError,
  TData = TQueryFnData,
  TQueryKey extends QueryKey = QueryKey,
> extends OmitKeyof<
  CreateBaseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>,
  'suspense'
> {}

注意两个关键实现细节:

  1. 继承的是 OmitKeyof<CreateBaseQueryOptions<...>, 'suspense'>,即在父类型基础上精确剔除了 suspense 一个属性OmitKeyof 工具类型定义在 query-core/src/types.ts,与标准 Omit 不同,它额外允许对“任意字符串键”做安全省略(TStrictly extends 'safely' 分支),这是为了兼容泛型展开后键类型不完全确定的场景。
  2. 继承链上父接口的第 4 个类型参数被固定填充为 TQueryFnData。对照 types.ts 第 21–33 行,CreateBaseQueryOptions 有 5 个泛型参数(其中第 4 个是 TQueryData),而 CreateQueryOptions 只有 4 个,因此在向下传递时把 TQueryData 直接写死为 TQueryFnData——这意味着对普通(非无限滚动)查询而言,“缓存中的数据形状”与“queryFn 返回的原始数据形状”是同一个。

为什么移除 suspense

suspense 是 React 特有的挂起机制。在 query-core 的 QueryObserverOptions 定义 中,其注释为:“If set to true, the query will suspend when status === 'pending' and throw errors when status === 'error'. Defaults to false.”。Angular 的查询通过 injectQuery 返回信号(Signal)化的结果对象来消费状态,并不存在 React 式 Suspense 边界,因此 Angular 包在类型层面直接移除该选项,避免开发者误以为可用。从源码结构看,CreateInfiniteQueryOptionstypes.ts 第 75–90 行)对 InfiniteQueryObserverOptions 同样做了 OmitKeyof<..., 'suspense'> 处理,二者保持一致的设计策略。

二、完整类型继承链

CreateQueryOptions 并非孤立接口,其能力来自一条清晰的继承链(每一环均可在仓库源码中查证):

CreateQueryOptions                              (angular-query-experimental/src/types.ts:35)
  └─ OmitKeyof<CreateBaseQueryOptions<...>, 'suspense'>
       └─ CreateBaseQueryOptions                (angular-query-experimental/src/types.ts:21)
            └─ QueryObserverOptions            (query-core/src/types.ts:315)
                 └─ WithRequired<QueryOptions, 'queryKey'>
                      └─ QueryOptions         (query-core/src/types.ts:231)
  • CreateBaseQueryOptions:定义在 types.ts 第 21–33 行extends QueryObserverOptions<TQueryFnData, TError, TData, TQueryData, TQueryKey>,本身不添加成员。参考文档 CreateBaseQueryOptions.md 描述了它与本接口唯一的不同:保留 5 个泛型参数(多出 TQueryData)且不剔除 suspense
  • QueryObserverOptions:定义在 query-core/src/types.ts 第 315 行起,在 QueryOptions 基础上要求 queryKey 必填(WithRequired<QueryOptions, 'queryKey'>),并补充了 enabledstaleTimerefetchInterval 等观察层选项。
  • QueryOptions:定义在 query-core/src/types.ts 第 231–281 行,承载 retrygcTimequeryFninitialData 等基础配置。

这条链也解释了参考文档中 Extends 一节为何把父类型写成 OmitKeyof<CreateBaseQueryOptions<TQueryFnData, TError, TData, TQueryFnData, TQueryKey>, "suspense"> 的形式——第 4 个实参 TQueryFnData 就是 Angular 层对 TQueryData 的固定绑定。

三、泛型参数逐一解读

参考文档列出了 CreateQueryOptions 的 4 个类型参数,结合 types.ts 第 35–39 行 的默认值与约束:

类型参数 默认值 约束 含义
TQueryFnData unknown 查询函数(queryFn)返回的原始数据类型,也是缓存中存储的数据类型(因 TQueryData 被固定为 TQueryFnData
TError DefaultError 错误类型。DefaultError 来自 query-core(types.ts 第 45–49 行),未通过模块增强声明 Register.defaultError 时即为 Error
TData TQueryFnData 最终对外暴露的数据类型。当配置了 select 选择器时,TDataTQueryFnData 不同,结果对象上的 data 即为 TData
TQueryKey QueryKey extends QueryKey 查询键类型,默认为 ReadonlyArray<unknown>,允许收窄为具体元组(如 ['post', number])以获得精确推断

这些参数并非仅用于展示:它们会一路传递到 QueryObserverOptions,进而约束 queryFnselectenabledstaleTime 等选项的签名。例如 enabled?: QueryBooleanOption<TQueryFnData, TError, TData, TQueryKey>query-core/src/types.ts 第 332 行),即允许传一个接收 Query 实例并返回 boolean 的函数。

四、可用配置项全览(继承自 QueryObserverOptions / QueryOptions)

CreateQueryOptions 自身没有任何声明成员(extends ... {} 为空),因此它的“配置项面”完全等于父类型去掉 suspense 后的集合。按来源分两层列出,默认值均以 query-core 源码注释为准:

4.1 观察层选项(来自 QueryObserverOptions)

选项 类型 默认值 说明(摘自源码注释)
enabled boolean | (query) => boolean true 设为 false 可禁用挂载/键变化时的自动拉取(types.ts:332
staleTime number | 'static' | (query) => ... 0 数据新鲜期(毫秒),设为 Infinity 永不过期(types.ts:339
refetchInterval number | false | (query) => ... false 设置后按该频率(毫秒)持续后台拉取(types.ts:345
refetchIntervalInBackground boolean false 标签页/窗口处于后台时是否继续 refetchInterval 拉取(types.ts:355
refetchOnWindowFocus boolean | 'always' | (query) => ... true 窗口聚焦时若数据过期则重新拉取;'always' 表示总是拉取(types.ts:363
refetchOnReconnect boolean | 'always' | (query) => ... truenetworkMode'always' 时除外) 网络重连时的拉取策略(types.ts:376
refetchOnMount boolean | 'always' | (query) => ... true 实例挂载时对已有查询的后台拉取策略(types.ts:389
retryOnMount boolean | (query) => boolean true 挂载时若查询带有错误,是否自动重试(types.ts:400
notifyOnChangeProps 属性名数组 | 'all' | 函数 追踪属性访问 控制哪些属性变化才触发结果通知(types.ts:408
throwOnError boolean | (error, query) => boolean false 是否将错误抛出而非放入 error 属性。在 Angular 中该机制由 createBaseQuery 在订阅回调里落地:命中 shouldThrowError(observer.options.throwOnError, ...) 时会 ngZone.onError.emit(state.error)throwcreate-base-query.ts 第 129–139 行
select (data: TQueryData) => TData 对缓存数据做变换/取子集,data 的类型随即变为 TDatatypes.ts:420
placeholderData 值或函数 initialData 且处于加载态时占位数据(types.ts:430
suspense 本接口已剔除,见第一节

4.2 基础层选项(来自 QueryOptions)

选项 类型 默认值 说明
queryKey TQueryKey 必填 查询唯一标识,由 WithRequired<QueryOptions, 'queryKey'> 强制(types.ts:322-L325
queryFn QueryFunction<TQueryFnData> | SkipToken 数据获取函数,接收 { client, queryKey, signal, meta, pageParam? } 上下文(QueryFunctionContext 定义
retry / retryDelay 布尔、数字或函数 QueryClient 默认值决定 失败重试策略(types.ts:244-L245
networkMode 'online' | 'always' | 'offlineFirst' 由客户端默认值决定 网络模式,并联动 refetchOnReconnect 的默认值
gcTime number 由客户端默认值决定 缓存数据成为未使用/非活动后在内存中保留的毫秒数,Infinity 禁用垃圾回收(types.ts:253
persister QueryPersister 包装 queryFn 的持久化钩子(types.ts:255
queryHash / queryKeyHashFn 字符串 / 函数 由 key 自动计算 自定义缓存哈希(types.ts:256-L258
initialData 值或 () => T | undefined 初始数据,可结合 initialDataUpdatedAttypes.ts:259-L260
structuralSharing boolean | 函数 true 结果间的结构化共享(types.ts:267-L269
behavior QueryBehavior 自定义查询行为
meta Record<string, unknown> 附加元数据载荷(types.ts:276
maxPages number 主要面向无限查询的页数上限,普通查询一般不涉及

提示:QueryClientdefaultQueryOptions 会为未显式提供的选项填充默认值。在 Angular 实现中,这一步发生在响应式管道里(见第五节),因此上表“由客户端默认值决定”的项最终取值取决于你在 provideAngularQuery 中传入的 QueryClient 配置。

五、CreateQueryOptions 的消费方式与运行时机制

该接口在 Angular 包中主要服务于两处 API:injectQuery 的第三个重载与 queryOptions 系列类型。

5.1 在 injectQuery 中的三个重载

injectQueryinject-query.ts 中提供三个签名(对应参考文档 injectQuery.md 的三份调用签名):

  1. 传入 DefinedInitialDataOptions(必有 initialData)→ 返回 DefinedCreateQueryResult
  2. 传入 UndefinedInitialDataOptionsinitialData 可为 undefined)→ 返回 CreateQueryResult
  3. 传入 CreateQueryOptions(无 initialData 约束)→ 返回 CreateQueryResult

后两个选项类型的定义位于 query-options.tsUndefinedInitialDataOptions 直接 CreateQueryOptions & { initialData?: ... }UnusedSkipTokenOptionsOmitKeyof<CreateQueryOptions, 'queryFn'> 排除 SkipToken 后重写 queryFn——可见 CreateQueryOptions 正是这些组合类型的底座。

官方文档给出的基础用法示例(来自 injectQuery.md):

class ServiceOrComponent {
  query = injectQuery(() => ({
    queryKey: ['repoData'],
    queryFn: () =>
      this.#http.get<Response>('https://api.github.com/repos/tanstack/query'),
  }))
}

响应式用法示例——回调中的信号表达式会被追踪,filter 变化为真值时查询自动启用,回退为假值时禁用:

class ServiceOrComponent {
  filter = signal('')

  todosQuery = injectQuery(() => ({
    queryKey: ['todos', this.filter()],
    queryFn: () => fetchTodos(this.filter()),
    // Signals can be combined with expressions
    enabled: !!this.filter(),
  }))
}

5.2 源码中的运行时链路

createBaseQuerycreate-base-query.ts)是 injectQueryinjectInfiniteQuery 的共同底座,它展示了选项对象如何被消费:

  1. 用户传入的 optionsFncomputed 中执行:queryClient.defaultQueryOptions(optionsFn())(第 58–64 行),因此传入的函数会在 Angular 响应式上下文中运行,其中读取的每个信号都成为依赖,信号变化即触发选项重算;
  2. 默认化后的选项通过 effect 中的 observer.setOptions(defaultedOptions) 交给 QueryObserver(第 89–106 行);
  3. 订阅通过 ngZone.runOutsideAngular 建立,状态变更再用 ngZone.run 回注到 resultFromSubscriberSignal(第 108–154 行),期间同步维护 Angular 的 PENDING_TASKSfetchStatus === 'fetching'pendingTasks.add()),使路由导航等机制能正确等待查询。

这段实现同时解释了 4.1 表中 throwOnError 的落地路径,以及为何 suspense 在 Angular 中被移除——错误处理与“等待”分别由错误抛出和 pending tasks 机制承担,而非挂起 UI。

5.3 queryOptions 辅助函数:跨组件复用选项

CreateQueryOptions 也是 queryOptions() 辅助函数三类重载(UndefinedInitialDataOptions / UnusedSkipTokenOptions / DefinedInitialDataOptions)的共同基类型,定义见 query-options.ts 第 76–171 行。该函数运行时只做透传(return options),价值在于类型层面:返回值的 queryKey 会被打上 QueryKeyWithDataTag 数据标签(query-core/src/types.ts 第 82–88 行),从而让 queryClient.getQueryData(queryKey) 获得精确类型。官方指南 query-options.md 给出的典型用法:

import { queryOptions, noop } from '@tanstack/angular-query-experimental'

@Injectable({ providedIn: 'root' })
export class QueriesService {
  private http = inject(HttpClient)

  post(postId: number) {
    return queryOptions({
      queryKey: ['post', postId],
      queryFn: () => {
        return lastValueFrom(
          this.http.get<Post>(
            `https://jsonplaceholder.typicode.com/posts/${postId}`,
          ),
        )
      },
    })
  }
}

// 组件/服务中使用:
postId = input.required({ transform: numberAttribute })
queries = inject(QueriesService)

postQuery = injectQuery(() => this.queries.post(this.postId()))

queryClient.query(this.queries.post(23)).catch(noop)
queryClient.setQueryData(this.queries.post(42).queryKey, newPost)

select 同样保证类型贯通:

// query.data 的类型是 select 的返回类型,而不是 queryFn 的返回类型
queries = inject(QueriesService)

query = injectQuery(() => ({
  ...groupOptions(1),
  select: (data) => data.title,
}))

六、小结

  • CreateQueryOptions 定义于 packages/angular-query-experimental/src/types.ts 第 35 行,是 CreateBaseQueryOptions 去除 suspense 后的收窄版本,4 个泛型参数 TQueryFnDataTErrorTDataTQueryKey 分别约束原始数据、错误、选择后数据与查询键的类型推断。
  • 它的全部配置能力继承自 query-core 的 QueryObserverOptionsQueryOptions,涵盖 enabledstaleTimerefetchIntervalrefetchOnWindowFocusretrygcTimeselectinitialDatathrowOnError 等选项及其默认值。
  • 它是 injectQuery 重载与 queryOptions 辅助函数的类型底座;运行时选项在 createBaseQuerycomputed 响应式管道中经 queryClient.defaultQueryOptions 默认化后交给 QueryObserver,这也是 Angular Query 支持信号驱动、响应式查询选项的根本机制。

如需继续深入,可参阅参考文档目录下的 CreateBaseQueryOptionsCreateInfiniteQueryOptionsInjectQueryOptions 以及 injectQuery 等关联页面。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389