资讯动态

Rome noConstAssign 规则深度解析:拦截 const 变量的非法重新赋值

发布时间:2026/9/20 12:38:49 来源:尧图企业网站定制
开发工具CLILint格式化静态分析代码质量构建工具【免费下载链接】toolsUnified developer tools for JavaScript, TypeScript, and the web项目地址https://gitcode.com/gh_mirrors/to/tools点击查看免费下载noConstAssign是 Rome 内置的正确性correctness类 lint 规则用于静态检测对const声明变量的一切重新赋值行为。本文以官方规则文档为骨架结合仓库中的规则实现、语义分析管线与测试用例系统讲解该规则的判定原理、诊断输出、边界情况与配置方法帮助你在实际项目中正确启用并理解其行为。规则概览规则名称noConstAssign源码内部标识为NoConstAssign所属分类lint/correctness/noConstAssign引入版本v10.0.0推荐状态推荐启用recommended即 Rome 默认开启该规则官方文档website/src/pages/lint/rules/noConstAssign.md规则的官方语义表述为阻止const变量被重新赋值re-assigned。在 JavaScript 运行时尝试给const变量赋值会抛出TypeError因此该问题属于典型的正确性缺陷应在编译期就被拦截而非留到运行时崩溃。在诊断分类层面该规则在 crates/rome_diagnostics_categories/src/categories.rs 中注册为lint/correctness/noConstAssign所有相关诊断都会携带这一稳定的分类标识便于下游工具如 IDE、CI统一处理。判定原理什么是重新赋值该规则关注的是 JavaScript 中所有会对变量写值的语法形式而不仅是简单的赋值。Rome 通过语义分析semantic analysis将赋值表达式与变量的声明绑定关联起来凡是命中以下任一形式、且目标变量由const声明都会被判定为违规语法形式示例说明直接赋值a 4最典型的形式复合赋值a 1、b - 2、c * 3复合赋值同样会写回变量自增 / 自减a、a--一元更新表达式多声明变量const a 1, b 2; a 2只对其中被赋值的const变量报错解构绑定变量const { i } obj; i 4从对象 / 数组解构出的const绑定同样受保护循环变量for (const k in obj) { k 4 }for...in/for...of的const循环变量无效示例Invalid以下四组代码均会被noConstAssign判定为错误诊断信息为Cant assign a because its a constant同时规则会在诊断中补充一条辅助信息This is where the variable is defined as constant将代码定位到const声明处帮助开发者快速找到变量定义位置。示例一直接赋值const a 1; a 4;诊断输出文件correctness/noConstAssign.jscorrectness/noConstAssign.js:2:1 lint/correctness/noConstAssign ━━━━━━━━━━━━━━━━━━━━━━ ✖ Cant assign a because its a constant 1 │ const a 1; 2 │ a 4; │ ^ ℹ This is where the variable is defined as constant 1 │ const a 1; │ ^主诊断定位在a 4的a第 2 行第 1 列辅助诊断定位到const a 1中的声明位置。示例二复合赋值const a 2; a 1;诊断定位在第 2 行的a 1。复合赋值在语义上等价于读取后写回因此同样违反const不可变性。示例三自增运算const a 1; a;诊断定位在第 2 行第 3 列的a。a以及a--、a对变量执行隐式写回同样被拦截。示例四多声明中的赋值const a 1, b 2; a 2;诊断定位在第 3 行的a 2。尽管a与b在同一条const语句中声明规则只针对实际被赋值的a报错。有效示例Validconst a 10; let b 10; b 20;const a 10声明后从未被赋值合法let b 10是可重新绑定的变量b 20属于合法操作不触发诊断。noConstAssign只约束const绑定let与var变量的重新赋值不在检查范围内。源码实现规则如何工作规则的完整实现位于 crates/rome_js_analyze/src/semantic_analyzers/correctness/no_const_assign.rs它属于 Rome 的语义分析器semantic analyzer而非纯语法分析器。语义分析器依托rome_js_semantic提供的语义模型能够将变量引用与变量声明绑定关联起来这是判断变量是否为const的前提。规则声明declare_rule! { /// Prevents from having const variables being re-assigned. /// /// Trying to assign a value to a const will cause an TypeError when the code is executed. pub(crate) NoConstAssign { version: 10.0.0, name: noConstAssign, recommended: true, } }该声明定义了规则的版本、名称与推荐状态文档元信息## Examples中的示例由rome_analyze的宏机制自动提取用于生成官方文档内容。规则的注册入口在 crates/rome_js_analyze/src/semantic_analyzers/correctness.rs通过declare_category!宏挂载到 correctness 分析类别下。查询类型与状态impl Rule for NoConstAssign { type Query SemanticJsIdentifierAssignment; type State TextRange; type Signals OptionSelf::State; type Options ();Query SemanticJsIdentifierAssignment规则只关注标识符赋值节点JsIdentifierAssignment即a 4中的a并由语义层驱动执行State TextRange命中时保存常量声明的文本区间供诊断阶段引用Options ()该规则不接受任何额外配置选项。核心判定逻辑fn run(ctx: RuleContextSelf) - Self::Signals { let node ctx.query(); let model ctx.model(); let declared_binding model.binding(node)?; if let Some(possible_declarator) declared_binding.syntax().ancestors().find(|node| { // 跳过解构模式中的中间节点对象属性、数组元素、标识符绑定等 !AnyJsObjectBindingPatternMember::can_cast(node.kind()) !JsObjectBindingPatternPropertyList::can_cast(node.kind()) !AnyJsArrayBindingPatternElement::can_cast(node.kind()) !JsArrayBindingPatternElementList::can_cast(node.kind()) !JsIdentifierBinding::can_cast(node.kind()) }) { if JsVariableDeclarator::can_cast(possible_declarator.kind()) { // ... 判断是 for 循环声明还是普通声明且 is_const() 为真 } } None }判定过程可以拆解为四步解析绑定通过语义模型model.binding(node)找到赋值标识符所绑定的声明回溯声明从绑定语法节点沿祖先链向上查找JsVariableDeclarator变量声明符。查找过程中会跳过对象解构成员、数组解构元素、绑定标识符等中间节点从而支持const { i, j: { l } } obj这类嵌套解构场景区分声明类型找到声明符后分别处理两种父结构——JsForVariableDeclarationfor (const k in ...)循环声明与JsVariableDeclaration普通变量声明语句校验 const 标志调用is_const()判断声明是否为const命中则返回常量声明的text_trimmed_range()作为状态。诊断消息生成fn diagnostic(ctx: RuleContextSelf, state: Self::State) - OptionRuleDiagnostic { let name node.name_token().ok()?; let name name.text_trimmed(); Some( RuleDiagnostic::new( rule_category!(), node.syntax().text_trimmed_range(), markup! {Cant assign Emphasis{name}/Emphasis because its a constant}, ) .detail(state, markup! {This is where the variable is defined as constant}), ) }诊断由两部分组成主诊断定位到赋值位置消息为Cant assign {变量名} because its a constantdetail辅助信息指向State中记录的常量声明区间输出This is where the variable is defined as constant。这正是文档示例中红色主诊断 蓝色辅助定位两段式输出的来源。测试用例边界场景与防误报验证仓库为该规则提供了独立的测试规格目录 crates/rome_js_analyze/tests/specs/correctness/noConstAssign/其中invalid.js是触发诊断的输入invalid.js.snap是快照断言。阅读invalid.jscrates/rome_js_analyze/tests/specs/correctness/noConstAssign/invalid.js可以看到远超官方文档四组示例的完整覆盖const a 1; a 2; const b 2, c 43; b 4; b; b 45; b--; function f() { b; } function f(d) { b; }这部分覆盖了直接赋值、多声明、复合赋值、自增自减以及嵌套函数体内对常量赋值的场景即使b在另一函数作用域内被修改语义分析仍能关联到外层const声明。解构与循环场景const { i, j: { l } } { i: 1, j: { l: 2 } }; i 4; l 4; for (const k in [1, 2]) { k 4; } const [p, { q }] [1, { q: 2 }]; p 3; q 4; const { r, ...rest } s; r 4;快照文件 crates/rome_js_analyze/tests/specs/correctness/noConstAssign/invalid.js.snap 中共记录了 14 条诊断包括a、b5 处不同赋值形式、i、l、k、p、q、r。值得注意的是invalid.js中还刻意包含了不应触发诊断的对照代码用于防止误报const fn (val) { val 0; }; // val 是函数参数不是 const 绑定不报错 const e () { try { foo(); } catch (err) { err 4; } }; // catch 参数不报错 const f (...rest) { rest 4; }; // rest 参数不报错 const g class bar {}; bar 1; // class 表达式名不报错 const h function foo() { foo 1; }; // 函数表达式名不报错这些用例验证了规则的一个关键设计只拦截const声明绑定本身的重新赋值而不会误伤函数参数包括普通参数、catch 参数、rest 参数以及 class / 函数表达式内部名称等非const绑定体现了语义分析相比纯正则匹配的精确性。配置与使用noConstAssign属于 recommended 规则Rome 默认启用无需额外配置即可生效。当需要显式调整其级别或关闭时可在项目根目录的rome.json中配置{ linter: { rules: { correctness: { noConstAssign: error } } } }可选值error默认recommended 规则生效级别触发时报告错误并导致检查失败warn仅输出警告不阻断流程off关闭该规则。规则的配置字段在 crates/rome_service/src/configuration/linter/rules.rs 中注册为no_const_assign并同步生成到 npm/rome/configuration_schema.json 的 JSON Schema 中编辑器可获得补全与校验支持。通过命令行运行检查对当前目录及子目录执行完整 lintrome check .诊断结果将以 CLI 报告形式输出格式与本文示例中的诊断快照一致。相关链接禁用规则Disable a rule规则选项Rule options规则官方文档源文件规则实现源码规则测试输入规则测试快照诊断分类注册小结noConstAssign是 Rome correctness 类别中最基础的常量保护规则之一它基于语义模型精准识别const绑定的重新赋值行为覆盖直接赋值、复合赋值、自增自减、多声明与解构绑定等全部写值形式同时通过严格的绑定回溯避免对函数参数、catch 参数等非const绑定产生误报。理解其底层实现语义绑定 声明符回溯 is_const()判定与测试覆盖14 条诊断 防误报对照有助于你在工程中正确启用该规则并将const语义错误消灭在编译期。赞分享开发工具CLILint格式化静态分析代码质量构建工具【免费下载链接】toolsUnified developer tools for JavaScript, TypeScript, and the web项目地址https://gitcode.com/gh_mirrors/to/tools点击查看免费下载相关推荐Rome Lint 规则 useConst 深度解析让从未重新赋值的变量强制使用 constRome Lint 规则 useConst 深度解析让从未重新赋值的变量强制使用 const 导读 本文围绕 Rome统一 JavaScript / Typ开发工具CLILint格式化静态分析代码质量构建工具ESLint prefer-const 规则全解析让所有不再赋值的变量都用 const 声明ESLint prefer const 规则全解析让所有不再赋值的变量都用 const 声明 本指南以 ESLint 内置规则 prefer const 为核开发工具Lint静态分析代码质量ESLint no-unassigned-vars 规则详解拦截被读取却从未赋值的 let/var 变量ESLint no unassigned vars 规则详解拦截被读取却从未赋值的 let/var 变量 no unassigned vars 是 ESLin开发工具Lint静态分析代码质量上一篇实时用户状态监控提升应用互动性的利器下一篇【亲测免费】 DeepCAD 项目使用教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价