ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TanStack Router create-route-property-order 规则详解:保障路由类型推断的属性顺序规范

TanStack Router create-route-property-order 规则详解:保障路由类型推断的属性顺序规范 TanStack Router create-route-property-order 规则详解保障路由类型推断的属性顺序规范【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router本文基于 TanStack Router 官方 ESLint 插件文档完整讲解create-route-property-order规则的设计动机、适用的四个路由创建函数、强制的属性顺序约束以及错误的/正确的代码写法并结合tanstack/eslint-plugin-router的源码实现与测试用例说明该规则如何识别间接调用、如何处理展开属性与顺序无关属性、以及自动修复autofix的工作原理。读完本文你可以在项目中正确配置该规则理解类型推断对属性顺序敏感的原因并能自行验证规则的边界行为。为什么对象属性的顺序会影响类型推断在 TypeScript 中对象字面量传给高阶泛型函数时类型推断是按属性“逐个”进行的。TanStack Router 的路由选项对象正是如此loader能访问到的context取决于beforeLoad的返回值beforeLoad又能引用更早定义的context来自loaderDeps/createRootRouteWithContext。因此属性书写的先后顺序直接决定了类型检查的结果——把loader写在beforeLoad前面loader的参数类型里就不会包含beforeLoad返回的对象。这正是官方文档 create-route-property-order 开宗明义指出的问题对于下列函数传入对象的属性顺序因类型推断而变得重要createRoutecreateFileRoutecreateRootRoutecreateRootRouteWithContextcreate-route-property-order规则的存在就是为了把“正确顺序”从口头约定变成 ESLint 可检查、可自动修复的硬性约束。正确的属性顺序文档给出的正确顺序分四个层级params、validateSearchloaderDeps、search.middlewares、ssrcontextbeforeLoadloaderonEnter、onStay、onLeave、head、scripts、headers、remountDeps除上述属性外其余所有属性对顺序不敏感因为它们不依赖类型推断。顺序约束在源码中的定义该顺序并非写死在规则逻辑里而是集中定义在 constants.ts 的sortRules中。它采用“相邻子集”的描述方式——每一行[A, B]表示 A 组属性必须出现在 B 组属性之前export const sortRules [ [[params, validateSearch], [search]], [[search], [loaderDeps, ssr]], [[loaderDeps], [context]], [[context], [beforeLoad]], [[beforeLoad], [loader]], [ [loader], [onEnter, onStay, onLeave, head, scripts, headers, remountDeps], ], ] as const从中可以看出两点同组内的属性如onEnter、onStay、onLeave、head等组内相对顺序不做要求只要求整组在loader之后params与validateSearch同属第一组二者之间的先后顺序被刻意忽略这在测试用例中有专门处理见下文“测试如何验证”。所有受检属性名则通过 create-route-property-order.utils.ts 中的getCheckedProperties从sortRules自动展平去重得到保证“文档顺序表”与“规则实现”始终同源。直接调用与间接调用的区别从源码 constants.ts 看四个函数被分为两类export const createRouteFunctionsIndirect [ createFileRoute, createRootRouteWithContext, ] as const export const createRouteFunctionsDirect [ createRootRoute, createRoute, ] as const直接调用createRootRoute、createRoute路由选项对象就是调用本身的第一个参数形如createRoute({ ... })间接调用createFileRoute、createRootRouteWithContext采用柯里化写法形如createFileRoute(/path)({ ... })对象位于外层调用。规则在 create-route-property-order.rule.ts 中对这两种形态分别处理let args node.arguments if (createRouteFunctionsIndirect.includes(createRouteFunction as any)) { if (node.parent.type AST_NODE_TYPES.CallExpression) { args node.parent.arguments // 柯里化从父调用中取对象 } else { return // 非柯里化形式跳过 } }这一细节解释了为什么createFileRoute(/path)({ ... })这样的两段式调用能被正确检查而没有第二段的中间表达式会被直接忽略。错误与正确的代码示例以下示例完整继承自官方文档React / Solid 两个框架的写法一致仅导入包名不同。错误示例loader写在beforeLoad之前/* eslint tanstack/router/create-route-property-order: warn */ import { createFileRoute } from tanstack/react-router export const Route createFileRoute(/path)({ loader: async ({ context }) { await context.queryClient.ensureQueryData(getQueryOptions(context.hello)) }, beforeLoad: () ({ hello: world }), })loader中使用的context.hello来自beforeLoad的返回值但beforeLoad写在后面loader参数类型推断不到hello导致类型错误。Solid 版本仅将导入换成tanstack/solid-router问题完全相同。正确示例beforeLoad在前loader在后/* eslint tanstack/router/create-route-property-order: warn */ import { createFileRoute } from tanstack/react-router export const Route createFileRoute(/path)({ beforeLoad: () ({ hello: world }), loader: async ({ context }) { await context.queryClient.ensureQueryData(getQueryOptions(context.hello)) }, })此时loader的context类型正确合并了beforeLoad返回的{ hello: string }context.hello类型检查通过ESLint 也不再告警。规则行为细节源码级阅读 create-route-property-order.rule.ts 可知规则的实际行为有几个明确边界只有两个及以上属性才检查。源码中if (allProperties.length 2) return第 67 行附近单属性对象无论怎么写都不会报错支持展开属性。...foo这类SpreadElement会被识别并参与排序要求展开目标是标识符否则抛出Unsupported spread element错误顺序无关属性原地保留。sortDataByOrder排序算法见 create-route-property-order.utils.ts只对受检属性集合内的属性做“稳定重排”其余属性如gcTime保持原有位置不动受检属性被插入到正确的相对位置仅在确实需要重排时才上报。sortDataByOrder返回null表示“已经有序”规则据此决定是否report避免无意义的告警与修复可自动修复Fixable: code。修复函数通过fixer.replaceTextRange将第一个属性起点到最后一个属性终点整个区间替换为按sortRules重排后的文本且保留了属性之间的原始空白/换行通过sourceCode.getText()切片原有分隔文本实现。规则的元信息定义为type: problem、docs.recommended: error、hasSuggestions: true、fixable: code即推荐启用、可自动修复。测试如何验证顺序逻辑规则测试位于 create-route-property-order.rule.test.ts其设计本身就值得借鉴使用combinate对“受测函数 × 属性组合”做笛卡尔积生成海量有效/无效用例通过generatePartialCombinations/generatePermutations/generateInterleavedCombinations三个工具函数见 test-utils.ts构造出“合法顺序的全排列有效用例”和“打乱顺序的插值排列无效用例含gcTime、...foo等顺序无关属性穿插其中”针对params与validateSearch测试显式跳过“二者相对顺序”的组合源码注释since we ignore the relative order of params and validateSearch与sortRules第一组“同组无序”的语义完全一致无效用例都携带output断言直接校验 autofix 修复后的代码是否等于期望的正确顺序另有两个手工补充的无效用例loader先于loaderDeps、head先于loader覆盖工具函数难以穷举的典型错误。如果你想本地复跑这套测试插件包位于 packages/eslint-plugin-router包含vite.config.ts、tsconfig.json与package.json等标准包配置。安装与配置该规则随独立发布的tanstack/eslint-plugin-router包提供见插件总览文档 eslint-plugin-router.md。按文档说明需要单独安装该开发依赖然后在配置文件中启用。Flat Configeslint.config.js推荐写法import pluginRouter from tanstack/eslint-plugin-router export default [ ...pluginRouter.configs[flat/recommended], // Any other config... ]只启用本规则的自定义 Flat Configimport pluginRouter from tanstack/eslint-plugin-router export default [ { plugins: { tanstack/router: pluginRouter, }, rules: { tanstack/router/create-route-property-order: error, }, }, // Any other config... ]Legacy Config.eslintrcESLint 9 之前的.eslintrc方式仍受支持{ extends: [plugin:tanstack/eslint-plugin-router/recommended] }或只启用单条规则{ plugins: [tanstack/eslint-plugin-router], rules: { tanstack/router/create-route-property-order: error } }规则属性一览按官方文档的 Attributes 章节该规则标记为Recommended包含在 recommended 配置中推荐启用Fixable支持--fix自动重排属性。小结create-route-property-order针对的是一类隐蔽问题路由选项对象中params/validateSearch→loaderDeps/search/ssr→context→beforeLoad→loader→onEnter/onStay/onLeave/head/scripts/headers/remountDeps的层级顺序直接决定类型推断的可用性。规则对createRoute、createFileRoute、createRootRoute、createRootRouteWithContext四种写法含柯里化都能识别支持展开属性、忽略顺序无关属性并能一键修复。将其加入 ESLint 配置后团队可以彻底告别“context里取不到beforeLoad数据”这类由书写顺序引发的类型报错。【免费下载链接】router A client-first, server-capable, fully type-safe router and full-stack framework for the web (React and more).项目地址: https://gitcode.com/GitHub_Trending/ro/router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表