首页
/ TanStack Query ESLint 插件:infinite-query-property-order 规则详解——无限滚动查询的属性顺序与类型推断

TanStack Query ESLint 插件:infinite-query-property-order 规则详解——无限滚动查询的属性顺序与类型推断

2026-09-05 22:32:59作者:裴锟轩Denise

对于在 React、Solid、Svelte、Vue 等框架中使用 TanStack Query 做无限滚动(infinite query)的开发者来说,infinite-query-property-order@tanstack/eslint-plugin-query 插件中一条针对类型推断敏感的代码风格规则:它要求 useInfiniteQueryuseSuspenseInfiniteQueryinfiniteQueryOptions 这三个函数在接收对象参数时,把 queryFngetPreviousPageParamgetNextPageParam 按固定顺序书写,否则 TypeScript 无法正确推断页面数据类型,进而导致编译错误或类型退化。读完全文,你将理解该规则的触发条件、正确写法,以及插件在源码层面如何实现检测与自动修复。

规则核心:哪些属性顺序敏感

官方规则文档 docs/eslint/infinite-query-property-order.md 指出,对于以下三个函数,传入对象的属性顺序会影响 TypeScript 的类型推断:

  • useInfiniteQuery
  • useSuspenseInfiniteQuery
  • infiniteQueryOptions

正确的属性顺序为:

  1. queryFn
  2. getPreviousPageParam
  3. getNextPageParam

其余属性(如 queryKeyinitialPageParammaxPages 等)对顺序不敏感,因为它们不参与这条类型推断链。

这一点可以从插件的规则常量文件得到印证。constants.ts 中定义了:

export const infiniteQueryFunctions = [
  'infiniteQueryOptions',
  'useInfiniteQuery',
  'useSuspenseInfiniteQuery',
] as const

export const checkedProperties = [
  'queryFn',
  'getPreviousPageParam',
  'getNextPageParam',
] as const

export const sortRules = [
  [['queryFn'], ['getPreviousPageParam', 'getNextPageParam']],
] as const

sortRules 的结构是一组 [前置集合, 后置集合] 的有序约束:queryFn 必须先出现,getPreviousPageParamgetNextPageParam 必须在它之后。这两个页面参数读取函数内部声明的回调参数(如 firstPagelastPage)类型依赖于 queryFn 返回的数据结构,若写在 queryFn 之前,TypeScript 在推断泛型时缺少上下文,就会导致类型推导失败。

规则示例:错误与正确写法

规则文档给出的错误示例——getNextPageParam 被提前到了 queryFn 之前:

/* eslint "@tanstack/query/infinite-query-property-order": "warn" */
import { useInfiniteQuery } from '@tanstack/react-query'

const query = useInfiniteQuery({
  queryKey: ['projects'],
  getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
  queryFn: async ({ pageParam }) => {
    const response = await fetch(`/api/projects?cursor=${pageParam}`)
    return await response.json()
  },
  initialPageParam: 0,
  getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
  maxPages: 3,
})

对应的正确写法——三个敏感属性按 queryFngetPreviousPageParamgetNextPageParam 顺序排列,其余属性位置不变:

/* eslint "@tanstack/query/infinite-query-property-order": "warn" */
import { useInfiniteQuery } from '@tanstack/react-query'

const query = useInfiniteQuery({
  queryKey: ['projects'],
  queryFn: async ({ pageParam }) => {
    const response = await fetch(`/api/projects?cursor=${pageParam}`)
    return await response.json()
  },
  initialPageParam: 0,
  getPreviousPageParam: (firstPage) => firstPage.previousId ?? undefined,
  getNextPageParam: (lastPage) => lastPage.nextId ?? undefined,
  maxPages: 3,
})

该规则在文档的 Attributes 一节中标记为 Recommended(推荐启用)Fixable(可自动修复),即开启 eslint --fix 即可自动重排属性。

规则元数据:报错级别与修复能力

规则本体定义于 infinite-query-property-order.rule.ts

export const rule = createPropertyOrderRule<
  InfiniteQueryFunctions,
  InfiniteQueryProperties
>(
  {
    name,
    meta: {
      type: 'problem',
      docs: {
        description:
          'Ensure correct order of inference sensitive properties for infinite queries',
        recommended: 'error',
      },
      messages: {
        invalidOrder: 'Invalid order of properties for `{{function}}`.',
      },
      schema: [],
      hasSuggestions: true,
      fixable: 'code',
    },
    defaultOptions: [],
  },
  infiniteQueryFunctions,
  sortRules,
)

meta 配置可以看到几个关键事实:

  • type: 'problem':被归类为真实问题而非单纯风格建议,因为顺序错误会直接造成类型推断失败;
  • recommended: 'error':在插件的推荐规则集中默认以 error 级别启用;
  • fixable: 'code'hasSuggestions: true:支持 --fix 自动修复;
  • 报错信息模板为 Invalid order of properties for \{{function}}`.,会填入具体函数名(如 useInfiniteQuery`);
  • schema: []:该规则不接受任何配置选项,开关即生效。

该规则通过 rules.ts 注册进插件的规则表,与 mutation-property-orderno-unstable-deps 等规则并列导出。

源码剖析:检测与自动修复是如何实现的

共享的规则工厂

该规则并未从零实现,而是复用了通用工厂函数 createPropertyOrderRule,它接收“目标函数列表”和“顺序约束规则”两个参数,生成完整的 ESLint 规则。其核心检测逻辑在 CallExpression 监听器中:

  1. 仅当调用目标是普通标识符(Identifier)且函数名命中目标列表(useInfiniteQuery 等)时才继续;
  2. 第一个参数必须是对象字面量(ObjectExpression),否则跳过;
  3. 对象属性少于 2 个时直接跳过(无需排序);
  4. 将每个属性映射为 { name, property },其中非标识符键(如计算属性)会被赋予占位名 _property_${index},从而不参与排序;
  5. sortDataByOrder 计算重排结果,若返回非空值说明存在顺序错误,随即调用 context.report 上报 invalidOrder 错误。

这一流程与文档描述完全一致:只有三个敏感属性违反顺序约束时才会报错,其他属性任意摆放都不会触发。

排序算法:只重排敏感属性,保持其余属性原地不动

sort-data-by-order.ts 实现了稳定的相对排序:

  • 先把排序规则展开为若干“子集”(对本规则即 [queryFn][getPreviousPageParam, getNextPageParam] 两个子集,前者优先);
  • 只筛选出属于这些子集的属性参与比较排序,同属一个子集的属性保持原有相对顺序;
  • 不在任何子集中的属性(如 queryKeyinitialPageParammaxPages)位置完全不变;
  • 若最终没有任何敏感属性被移动(wasResortedfalse),返回 null,规则因此不报错。

这解释了文档中“其余属性对顺序不敏感”的原因:排序算法在设计上就只移动三个受检属性,其余属性在修复后也保持原位。

自动修复:保留属性间的原始文本

工厂函数中的 fix(fixer) 回调负责生成修复文本:它按排序后的属性顺序,逐个取属性的源码文本拼接,并夹入相邻属性之间原有的间隔文本(注释、空行等):

let textBetweenProperties = ''
if (index < allProperties.length - 1) {
  textBetweenProperties = sourceCode
    .getText()
    .slice(allProperties[index]!.range[1], allProperties[index + 1]!.range[0])
}

最终通过 fixer.replaceTextRange 将首个属性到最后一个属性的整段文本替换为重排后的文本。也就是说,eslint --fix 只重排敏感属性的位置,属性之间的手写格式内容会被原样搬运。

仅在 TanStack Query 导入上生效

一个重要的边界条件来自 detect-react-query-imports.ts。所有插件规则都被 detectTanstackQueryImports 包装,只有当函数确实是从 @tanstack/ 开头、以 -query 结尾的包(如 @tanstack/react-query)中具名导入时,检测才生效:

node.source.value.startsWith('@tanstack/') &&
node.source.value.endsWith('-query')

因此,如果项目里有一个自定义的同名 useInfiniteQuery 工具函数,该规则不会误报;反过来,从 @tanstack/react-query 导入的调用则会被完整检查。该包装器通过收集 ImportDeclaration 中所有导入说明符、再在规则执行前判断标识符是否来自上述包名来实现精确匹配。

测试验证

仓库提供了对应的单元测试文件 infinite-query-property-order.rule.test.ts,位于插件的 tests 目录 下,与文档中的正/误示例共同构成该规则行为的回归保障;排序算法本身另有 sort-data-by-order.utils.test.ts 覆盖,可用于验证“只重排敏感属性、其余属性保持原位”的行为。

实践要点小结

  • 何时触发:对象参数形式调用 useInfiniteQuery / useSuspenseInfiniteQuery / infiniteQueryOptions,且第一个参数为对象字面量、含两个以上属性时;
  • 必须遵守的顺序queryFngetPreviousPageParamgetNextPageParamqueryKeyinitialPageParammaxPages 等其他属性可随意放置;
  • 报错与修复:报错信息会指明具体函数名(Invalid order of properties for \useInfiniteQuery`.),执行 eslint --fix` 可自动重排,且仅移动敏感属性;
  • 推荐级别:插件推荐集中默认以 error 级别启用(文档标注 Recommended);
  • 误报防护:规则只检查从 @tanstack/*-query 包导入的函数,自定义同名函数不受影响。

把该规则加入团队的 ESLint 配置后,属性顺序错误会在提交前被静态发现并可一键修复,从而避免无限滚动查询因属性书写顺序不同而在不同文件中出现类型推断失败的问题。

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