发布时间:2026/9/7 9:44:16
TanStack Query ESLint 规则 no-void-query-fn 深度解析:如何用类型感知检查拦截“返回 void 的 queryFn” TanStack Query ESLint 规则 no-void-query-fn 深度解析如何用类型感知检查拦截“返回 void 的 queryFn”【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/queryTanStack Query 的queryFn的返回值会被写入缓存并暴露给订阅者一旦它实际返回void/undefined组件拿到的将永远是空数据且这类错误往往难以在运行时察觉。本文基于仓库内的官方规则文档 no-void-query-fn.md 与其实现源码 no-void-query-fn.rule.ts完整讲解tanstack/eslint-plugin-query中no-void-query-fn规则的动机、正误示例、类型感知检测原理、覆盖的 API 边界与接入配置帮助你把这类“忘记 return”的隐患拦截在静态检查阶段。规则动机queryFn 必须返回可被缓存的值规则文档开篇给出的核心约束是Query functions must return a value that will be cached by TanStack Query. Functions that dont return a value (void functions) can lead to unexpected behavior and might indicate a mistake in the implementation.即queryFn必须返回一个会被 TanStack Query 缓存的值。不返回值的函数void 函数会导致不可预期的行为通常意味着实现上的失误。一个典型的失误场景是在异步函数里await了网络请求却忘记把结果return出去——请求确实发出了但缓存里写入的是undefined界面表现为“请求成功但数据为空”这类 bug 在运行时很难定位。错误示例规则文档给出的incorrect代码/* eslint tanstack/query/no-void-query-fn: error */ useQuery({ queryKey: [todos], queryFn: async () { await api.todos.fetch() // Function doesnt return the fetched data }, })正确示例对应的correct写法显式把请求结果返回/* eslint tanstack/query/no-void-query-fn: error */ useQuery({ queryKey: [todos], queryFn: async () { const todos await api.todos.fetch() return todos }, })规则属性Recommended推荐启用在插件预设中默认以error级别开启不可自动修复Not Fixable规则只做报告不提供 auto-fix。这一点可以从插件入口 index.ts 的预设配置得到印证recommendedRules中显式声明了tanstack/query/no-void-query-fn: error并被recommended、recommendedStrict、flat/recommended、flat/recommended-strict四套预设统一引用规则自身 meta 中也标注了recommended: error见 规则实现。实现原理一只对导入 tanstack/*-query 的文件生效规则本体通过工具函数detectTanstackQueryImports包装规则实现 L27。该函数位于 detect-react-query-imports.ts其逻辑是监听文件中的ImportDeclaration节点仅当导入来源以tanstack/开头且以-query结尾且为 value 导入时记录该导入的所有命名导入将原始规则指令与检测指令合并到同一个 listener 中执行。因此该规则天然具备“作用域隔离”特性只有真正从tanstack/react-query、tanstack/vue-query、tanstack/solid-query、tanstack/svelte-query、tanstack/svelte-query等框架包引入 API 的文件才会被检查同名的业务函数不会触发误报。实现原理二定位 queryFn 属性并做类型检查规则的核心监听器挂在Property节点上规则实现 L29-L67判断条件是父节点必须是对象字面量ASTUtils.isObjectExpression(node.parent)属性键必须是名为queryFn的标识符ASTUtils.isIdentifierWithName(node.key, queryFn)。命中后再执行一次“类型信息可用性检查”const parserServices context.sourceCode.parserServices if ( !parserServices || !parserServices.esTreeNodeToTSNodeMap || !parserServices.program ) { return }从源码结构看这是一条类型感知type-aware规则只有当 ESLint 使用typescript-eslint/parser并开启项目感知解析即parserOptions.project或projectService使 TypeScript 程序与类型映射可用时规则才会工作缺少类型服务时会静默跳过而不是报错。具备类型服务后规则获取queryFn值表达式的 TypeScript 类型取第一个调用签名并读取其返回类型const checker parserServices.program.getTypeChecker() const tsNode parserServices.esTreeNodeToTSNodeMap.get(node.value) const type checker.getTypeAtLocation(tsNode) if (type.getCallSignatures().length 0) { const returnType type.getCallSignatures()[0]?.getReturnType() if (!returnType) return if (isIllegalReturn(checker, returnType)) { context.report({ node: node.value, messageId: noVoidReturn }) } }报错消息固定为queryFn must return a non-undefined valuemessageIdnoVoidReturn报告位置指向queryFn的属性值节点。isIllegalReturnawait 解包 联合类型递归判定逻辑集中在 isIllegalReturnfunction isIllegalReturn(checker: TypeChecker, type: Type): boolean { const awaited checker.getAwaitedType(type) if (!awaited) return false if (awaited.isUnion()) { return awaited.types.some((t) isIllegalReturn(checker, t)) } const typeString checker.typeToString(awaited) return typeString void || typeString undefined }三个关键设计决定了规则的精度checker.getAwaitedType(type)先对返回类型做 await 解包。Promisevoid会先解包为void再比对因此无论是同步返回void、返回Promisevoid、还是async函数隐式返回Promisevoid都能被统一识别联合类型递归若解包后的类型是联合类型例如{ data: string } | undefined只要其中任一成员是void/undefined即视为非法——这对应测试中“三元表达式某分支返回 undefined”“if 分支缺少 return 隐式产生 undefined”等 case字符串精确比对最终通过typeToString只匹配void与undefined两个精确字符串。这意味着null、0、false这类“合法但 falsy”的数据类型不会误报测试用例queryFn returns null、queryFn returns 0、queryFn returns false均列为 valid。测试用例揭示的覆盖范围与边界no-void-query-fn.test.ts 使用typescript-eslint/rule-tester并显式配置parserOptions: { project: true, tsconfigRootDir: ts-fixture }来保证类型感知环境其 valid/invalid 用例恰好勾勒出规则的完整能力边界覆盖的 API 面invalid 用例中均会报错调用面是否检查useQuery/useInfiniteQuery/useSuspenseQuery✅ 报错queryOptions工厂函数中的 queryFn✅ 报错queryClient.fetchQuery/prefetchQuery✅ 报错queryClient.prefetchInfiniteQuery/ensureQueryData/ensureInfiniteQueryData✅ 报错由于规则只看“对象字面量中键名为queryFn的属性”并不绑定外层调用者所以上述所有接受queryFn的入口都被自然覆盖——这是一个从源码结构看得到的泛化收益新增的 Query API 只要沿用queryFn选项名无需改规则即可继续受检。会被判为非法的形态均触发noVoidReturn同步/异步函数体无 return隐式undefined/void显式声明(): Promisevoid() Promise.resolve(undefined)传入外部定义的async function voidOperation(): Promisevoid作为queryFn类型检查基于实参类型而非字面量形态条件分支中“一个分支返回数据、另一分支缺失 return”三元表达式其中一个分支为undefined联合类型递归命中;try/catch中 try 分支有 return、catch 分支无 return隐式undefined并入联合类型。不会被误报的形态返回对象、Promise数据、Promise.resolve(数据)、显式PromiseData/ 泛型PromiseResponseT外部 async 函数返回Promise{ data: string }返回null、0、false返回数字枚举、字符串枚举、const enum成员以及 async 函数返回枚举成员useInfiniteQuery正常返回页数据、prefetch*/ensure*返回r.json()等。这些用例共同说明规则的目标是**“返回类型在 await 解包后仍含 void/undefined 成员”**而不是粗暴地要求“必须有 return 语句”。接入方式与适用前提该规则随 npm 包tanstack/eslint-plugin-query发布package.json当前仓库内版本 5.102.8规则在 rules.ts 中注册。使用时的关键前提与配置需要 TypeScript 类型信息。由于规则依赖parserServices.program与esTreeNodeToTSNodeMapESLint 必须使用typescript-eslint/parser并配置项目感知parserOptions.project: true或projectService。缺少类型服务时规则静默不检查不会导致 lint 崩溃——但也意味着漏报。版本兼容范围包声明的 peerDependencies 为eslint ^8.57.0 || ^9.0.0 || ^10.0.0typescript ^5.6.0 || ^6.0.0 || ^7.0.0可选见 package.json在纯 JS无类型服务项目中该规则实际不生效。启用方式直接采用预设即可规则已包含在推荐集中且级别为error// flat config import query from tanstack/eslint-plugin-query export default [query.configs[flat/recommended]]若只想单独启用/调整该规则可在rules中显式声明tanstack/query/no-void-query-fn: error。无选项、不可自动修复规则schema: []不接受任何配置项且由于“补上 return”涉及业务意图判断meta 未提供 fixer文档 Attributes 中标注 Fixable 未勾选修复需人工处理。小结规则的设计取舍no-void-query-fn体现了 TanStack Query ESLint 插件的一条设计主线用类型系统换取静态检查的深度。它以对象字面量中queryFn键名为锚点借getAwaitedType统一处理同步/异步返回再对联合类型做递归判定从而在不依赖代码形态内联函数、外部函数引用、工厂函数、queryClient命令式 API的情况下准确识别“会缓存出空值”的 queryFn。同时它通过导入检测限定作用域、通过类型服务可用性检查保证降级安全配合预设默认error级别使“忘记 return 请求结果”这一 TanStack Query 项目中最隐蔽的失误类别在 lint 阶段即可被稳定捕获。【免费下载链接】query Powerful asynchronous state management, server-state utilities and data fetching for the web. TS/JS, React Query, Solid Query, Svelte Query and Vue Query.项目地址: https://gitcode.com/GitHub_Trending/qu/query创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

2026/9/7 9:39:13

AI写专著高效之道:实测AI工具,1天完成20万字专著初稿!

创新是学术专著的核心,也是写作时最难跨越的障碍。一部合格的专著,不仅仅是把已有的研究内容简单拼凑起来,更需要从头到尾提出独特的观点、理论体系或者研究方法。在海量的学术资料中,想找到真正没被探讨过的空白点非常困难。要么…

2026/9/7 9:39:13

超实用!AI专著生成工具揭秘,一键搞定20万字专业专著写作

AI专著写作:智能工具的助力与优势 撰写严谨的学术专著,离不开大量资料和数据的支持,可是搜集信息和整理数据往往是最费时又复杂的部分。研究人员不仅需要广泛查阅国内外的最新文献,保证引用的是权威且相关的内容,还得…

2026/9/7 20:30:52

npx skills 安装 Skill 到本地:从原理到实战

最近一直在折腾 Claude Code、Codex 和 Cursor 这几个 AI 编程工具,发现社区里讨论热度最高的词已经从 MCP 悄悄变成了 Skill。尤其是一句“用 npx skills 装一个 Skill 到本地”,最近几乎每天都能在群里看到。但问了一圈,真正把这套流程跑明…

2026/9/7 20:30:52

插件系统中的数学插件精度问题与实战处理方案

搞插件系统最容易被忽视、又最容易翻车的,往往不是插件加载机制,也不是通信协议,而是数学插件里的计算精度。 我去年在做一套离线渲染器的插件框架时,接了一个第三方写的向量数学插件。功能一切正常,速度也挺快&#…

2026/9/7 20:30:52

共享内存 多进程并发竞争:非原子操作引发数据丢失

一、基础概念 1. 共享内存 共享内存是 Linux 常用 IPC 通信方式,由内核开辟一块独立物理内存,允许多个进程同时映射、读写同一份数据,是多进程数据共享的核心方案。 2. 非原子操作与竞态条件 原子操作:一次性执行完成&#xf…

2026/9/7 20:30:52

微服务与领域驱动设计:构建高内聚低耦合系统的指南

目录 一、微服务架构模型的对比与选择 (一)整洁架构 (二)六边形架构 (三)DDD 分层架构 1.用户接口层 2.应用层 3.领域层 4.基础层 5.从三层架构向 DDD 分层架构演进 (四)三种微服务架构模型的对比和分析 二、领域驱动设计分层架构与微服务代码模型 (一)代…

2026/9/7 20:30:52

AI生成结果可靠性验证:测试用例设计与验证点构建全指南

我们组上个月接了一个客服知识问答AI的验收测试,需求方一开始给的验收标准只有一句话:“回答要准确、不能乱说”。这句话让整个测试组头疼了两周——准确怎么定义?乱说怎么判断?同一个问题今天答对明天答错算不算bug?更…

2026/9/7 20:25:52

前置机数据同步用哪种方案?实时比对和定时补偿

前置机数据同步最麻烦的地方在于,链路监控全是绿的,业务侧却时不时冒出一条旧数据。系统替代那段时间,内外网两边的库并行跑,每天早上对账脚本跑出来的差异少则几十条,多的时候上千条,追查下去无非两类原因…

2026/9/7 0:47:43

超人会飞不算本事:系统稳定依赖清晰规则与边界设计

开头先不绕弯子。“#斯坦李吐槽dc 所以超人是无缘无故会飞的嘛哈哈哈哈哈哈哈锤哥真是技术人才啊!#雷神 #复联”这类调侃式短标题,第一波冲击力在于它把两个宇宙的角色塞进同一个吐槽箱里,但细想一下就能发现,它真正碰到的根本不是…

2026/9/7 0:14:19

超人VS蜘蛛侠:拆解超级IP的影响力与传播方法论

把“蜘蛛侠 vs 超人”放在 CSDN 上聊,可能很多人第一反应是走错片场了。但如果把这两个角色看成“两个持续运营了 80 多年的文化产品”,你会发现,这场比较本质上是两个不同 IP 策略的长期结果对比:超人赢在定义了整个超级英雄题材…

2026/9/7 0:14:17

基于CNN的调制信号识别:MATLAB实现时频图分类实战

简介:本资源是一套面向通信工程与信号处理方向学习者、研究者的深度学习实践方案,聚焦调制信号自动检测与识别这一典型无线通信任务,解决传统方法依赖人工特征、低信噪比下性能下降等痛点。压缩包共12个文件(10.73MB)&…

2026/9/7 0:03:36

基于YOLOv8和PyQt5的麦穗稻穗检测识别系统设计与实现

这次我们来看一个把目标检测算法和桌面端工具结合得很典型的项目:基于 YOLOv8 PyQt5 的麦穗稻穗检测识别系统。这个项目本身不是新概念,但它的价值在于落地形态很完整。YOLOv8 负责核心的麦穗稻穗目标检测,PyQt5 负责提供可视化的桌面交互界…

2026/9/7 0:03:36

UL 1642锂电池安全标准全解析:测试项目、认证流程与避坑指南

简介:UL 1642是锂电池安全领域的重要规范,本中文版资源适合锂电池制造商、检测机构工程师及产品认证相关人员阅读,用于理解电池在设计与制造层面的安全要求、测试方法与合规要点。资源共1个PDF文件,压缩包大小834KB,便…

2026/9/7 0:03:36

BS EN 13814-1-2019游乐设施安全标准:设计与制造核心要点解析

简介:BS EN 13814-1:2019是英国采纳欧洲标准EN 13814-1:2019的正式版本,由BSI标准出版,重点规定游乐设施和游乐设备在设计与制造环节的安全准则,与BS EN 13814-2:2019、BS EN 13814-3:2019共同取代旧版BS EN 13814:2004。该标准面…

2026/9/7 16:23:03

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/6 19:33:50

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/6 10:19:40

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…