恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
eslint-plugin-unicorn 的 no-non-function-verb-prefix 规则:让 `getName`、`createPizza` 这类动词前缀命名必须指向可调用值
首页
资讯中心
/
eslint-plugin-unicorn 的 no-non-function-verb-prefix 规则:让 `getName`、`createPizza` 这类动词前缀命名必须指向可调用值
eslint-plugin-unicorn 的 no-non-function-verb-prefix 规则:让 `getName`、`createPizza` 这类动词前缀命名必须指向可调用值
发布时间:2026/9/18 23:52:36
eslint-plugin-unicorn 的 no-non-function-verb-prefix 规则让getName、createPizza这类动词前缀命名必须指向可调用值【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn导读eslint-plugin-unicorn是一个提供超过 300 条 ESLint 规则的开源插件其中no-non-function-verb-prefix专门解决一类命名与类型错配的问题当一个标识符以get、set、create等函数式动词开头时读者会天然预期它是一个可调用callable或可构造constructable的值。本文基于该规则的官方文档、完整源码实现与 AVA 快照测试系统讲解规则的判定语义、26 个典型违规样例、类型系统层面的可调用性分析原理以及verbs与ignore两个配置项的实际用法。读完本文你将能够精确掌握该规则在类型感知type-awarelinting 下的行为边界并能在自己的 TypeScript 项目中正确配置与使用它。该规则的核心文档位于 docs/rules/no-non-function-verb-prefix.md完整实现位于 rules/no-non-function-verb-prefix.js测试用例与快照分别位于 test/no-non-function-verb-prefix.js 和 test/snapshots/no-non-function-verb-prefix.js.md。规则语义动词前缀名应当指向可调用值官方文档对该规则的描述是禁止对具有函数式动词前缀的绑定使用非函数值Disallow non-function values with function-style verb prefixes。其背后是代码可读性共识——名字以get、set、create等动词开头的标识符如果实际绑定的是一个字符串、数字或普通对象就会严重误导阅读者// ❌ getName 是一个字符串却叫获取名字 const getName Sindre; // ✅ 让 getName 真正成为一个函数 const getName () Sindre;// ❌ createPizza 不是创建披萨的函数而是披萨实例 const createPizza new Pizza(); // ✅ 语义与命名一致 const createPizza () new Pizza();该规则由 rules/no-non-function-verb-prefix.js 实现其 meta 信息显示规则类型为suggestion在recommended配置中默认启用在unopinionated配置中禁用同时声明requiresTypeChecking: true即必须开启类型感知 linting 才能生效。源码中还有一道硬性门槛create函数会先检查isTypeScriptFile(context.physicalFilename)与parserServices?.program是否存在二者任一不满足就直接返回因此该规则只在 TypeScript 文件且有类型信息时运行对纯 JavaScript 项目完全无副作用。快照测试全景26 个违规样例逐一解析仓库用 AVA 快照测试锁定了规则的输出行为test/snapshots/no-non-function-verb-prefix.js.md共 26 个 invalid 用例。每个用例都附带输入代码、错误位置caret与消息文本。这些用例覆盖了绑定声明的几乎所有语法形态值得逐一梳理。变量声明最常见的违规场景用例输入触发动词invalid(1)const getName name;getinvalid(2)class Pizza {} const createPizza new Pizza();createinvalid(3)const removeItem: Promisevoid Promise.resolve();removeinvalid(20)const addItem 1;addinvalid(21)const deleteItem true;deleteinvalid(22)const setItem 1;setinvalid(23)const unsetItem 1;unsetinvalid(24)const destroyItem 1;destroy其中 invalid(2) 很典型createPizza的值类型是Pizza的实例虽然Pizza类本身可构造但实例类型并不具备可调用/可构造签名因此被判定为违规invalid(3) 中removeItem的类型是Promisevoid同样不可调用。invalid(20)~(24) 则集中展示了默认动词表中除get/create外的其余动词add、delete、set、unset、destroy。函数参数与解构参数名同样受约束规则不仅检查变量声明还检查函数参数绑定invalid(4)function run(getName: string) { return getName; }——普通类型参数invalid(5)function run({getName}: {getName: string}) { return getName; }——对象解构参数invalid(18)function runT extends string(getName: T) { return getName; }——泛型参数约束为string因此可调用性判定为不可调用。在源码的create中规则监听了FunctionDeclaration、FunctionExpression、ArrowFunctionExpression三类节点遍历其params并递归收集绑定标识符。类成员字段、私有字段与 accessor类内绑定覆盖了三种形态invalid(9)class Person { getName name; }——普通实例字段invalid(10)class Person { #getName name; }——私有字段错误位置包含#invalid(11)class Person { accessor getName name; }——自动 accessor 字段invalid(12)class Person { getName: object () name; }——显式标注object类型invalid(6)class Person { constructor(public getName: string) {} }——构造器中的 TS 参数属性TSParameterProperty。invalid(12) 特别说明问题右侧初始值明明是箭头函数但显式标注的object类型决定了可调用性判定——规则以类型注解为准而非初始化表达式。解构声明属性重命名也不放过invalid(7)const {getName} object as {getName: string};——直接解构invalid(8)const {foo: getName} object as {foo: string};——重命名解构检查的是目标绑定名getName而非源属性名foo。导入绑定默认导入、命名导入与命名空间导入invalid(14)import getName from ./module;——默认导入invalid(15)import {name as getName} from ./module;——命名导入别名invalid(16)import * as getModule from ./module;——命名空间导入invalid(17)import getModule require(./module);——TSimport require语法。其中 invalid(17) 对应源码对TSImportEqualsDeclaration节点的监听而type关键字标记的纯类型导入如import type getName from ./module会被跳过因为isTypeOnlyImport会检查importKind。枚举与联合类型invalid(19)enum getName { value }——枚举成员不可调用invalid(13)let getName: string | (() string);——联合类型一部分string不可调用因此整体判定为不可调用。invalid(13) 是理解规则类型分析策略的关键案例详见下文源码解析。错误消息格式精确到标识符与动词快照显示所有违规使用同一条消息模板定义于源码第 29-31 行getName starts with get, so it should be a function.消息由{{name}}与{{verb}}两个占位符填充且错误范围range精确指向标识符本身。以 invalid(1) 为例 1 | const getName name; | ^^^^^^^ getName starts with get, so it should be a function.caret 下方即违规标识符getName对于私有字段invalid(10)范围包含#^^^^^^^对于类型标注完整的绑定invalid(3)、invalid(13)范围可能覆盖整条声明因为类型信息来自注解节点。源码级解析规则的判定流水线动词匹配前缀 大写字母检查默认动词表定义于 rules/no-non-function-verb-prefix.jsconst defaultVerbs [ get, set, unset, delete, add, remove, destroy, create, ];匹配算法getVerbPrefix源码第 43-52 行有两个要点名称必须以动词开头动词之后的字符必须是大写 ASCII 字母isUppercaseAscii检查A~Z。第二点解释了为什么getter、get_name、GET_NAME这些名字不会被误报它们也出现在测试的 valid 用例中——只有驼峰式动词前缀如getName才符合函数式命名的直觉。类型可调用性分析核心判定逻辑匹配到动词后规则通过 TypeScript 编译器 APIparserServices获取绑定位置的类型调用getTypeCallability源码第 146-189 行递归分析未知/空类型直接放行unknown、nullish类型、never返回unknown状态不报告。这也解释了为何function run(getName: unknown)、function run(getName: any)、declare const getName: never都是合法用例可调用/可构造类型存在调用签名getCallSignatures或构造签名getConstructSignatures即视为可调用此外标准库的Function、CallableFunction、NewableFunction类型也通过isDefaultLibraryCallableType被认定为可调用该集合定义于源码第 24-28 行工具函数来自 rules/utils/type-helpers.js联合类型过滤掉 nullish 成员后所有成员都可调用才判为可调用任一成员不可调用即整体违规——这正是 invalid(13)string | (() string)被报告的原因全部成员未知则放行交叉类型任一成员可调用即可通过因交叉类型同时具备各方能力泛型参数解析其约束constraint后递归分析因此T extends string会被推导为不可调用invalid(18)而T extends () string或裸T约束未知则放行getBaseConstraintOfType处理类型别名等间接约束后继续递归环检测通过visitedTypes集合防止递归分析陷入循环。最终只有当动词匹配且类型确定为不可调用nonCallable时才报告问题。静默跳过的场景源码在getProblem第 191-226 行与各节点监听器中还有一系列网开一面的规则声明模块declare module/declare namespace内的绑定不检查isInDeclaredModule纯类型导入import type与type限定导入不检查declare类字段、抽象字段不检查——因此 valid 用例中declare getName: string、abstract getName: string、declare class Person { getName: string }全部通过const enum与declare enum不检查源码第 274-283 行函数自身声明function getName() {...}天然可调用不会误报对象字面量属性、类的方法/getter/setter不在检查范围内因为规则的监听列表只包含绑定类节点变量声明、导入、参数、类字段、枚举const object {getName: name}与class Person { get getName() {...} }均为合法用例。配置项详解verbs 与 ignoreverbs自定义动词前缀集合类型为Arraystring默认值为上述 8 个动词。文档规定只有动词后紧跟大写字母的驼峰命名会被检查。配置示例来自 docs/rules/no-non-function-verb-prefix.md/* eslint unicorn/no-non-function-verb-prefix: [error, {verbs: [build]}] */ // ❌ const buildName name; // ✅ const buildName () name;对应快照中的 invalid(25)配置verbs: [build]后const buildName name被报告消息为buildName starts with build, so it should be a function.。源码中prepareOptions还会将自定义动词按长度降序排序确保长动词如unset优先于短动词如set参与匹配避免前缀冲突。ignore按正则忽略指定名称类型为Arraystring | RegExp默认[]。字符串会被当作正则表达式处理除非用^与$锚定否则会匹配名称中任意位置源码第 137-144 行会重置lastIndex以支持带全局标志的正则。文档示例unicorn/no-non-function-verb-prefix: [ error, { ignore: [ ^addOns$, ], }, ]配置后const addOns [cheese, pineapple];通过检查invalid(26) 的反向验证const addPizza new Pizza()仍被报告因为addPizza不匹配^addOns$。测试中还验证了字符串形式与RegExp字面量形式等价{ignore: [^addOns$]}与{ignore: [/^addOns$/]}行为一致且{ignore: [/^addO/g]}可同时忽略addOns与addOptions。反向验证valid 用例揭示的边界test/no-non-function-verb-prefix.js 中共 50 余个 valid 用例除了上文已提及的跳过场景外还验证了几类关键边界非驼峰命名getter、get_name、GET_NAME不匹配动词前缀规则可调用值const getName () name、const getName: () string () name、const getName: (() string) {property: string}交叉类型均通过标准库函数类型类型为Function、CallableFunction、NewableFunction的绑定通过可调用工厂返回值const getName makeFactory()返回() string通过说明分析会沿类型流动而非只看声明形式类引用const createPizza: typeof Pizza Pizza通过构造签名无类型信息时纯 JS 文件file.js与未启用 project 服务的 TS 文件中的const getName name均不报错印证了必须开启类型感知 linting的前提。测试通过typescriptEslintParser与projectService加载 test/fixtures/no-non-function-verb-prefix/tsconfig.json 下的 module.ts 提供模块类型信息导入类用例invalid(14)~(17)正是依赖该 fixture 完成类型解析。在自己的项目中启用该规则由于规则依赖类型信息使用前需确保项目使用TypeScript且 ESLint 配置了typescript-eslint/parser并开启类型感知在 parserOptions 中配置project或projectService使用 flat config 时将插件配置为unicorn/no-non-function-verb-prefix: error。若使用recommended预设该规则会自动启用recommended: true无需手动声明若使用unopinionated预设需手动开启。运行方式与普通 ESLint 规则一致例如npx eslint .规则只会在.ts/.tsx文件上产生诊断。若某些动词前缀命名确为有意为之如工具库中的addOns配置对象可通过ignore选项用锚定正则精确放行若团队习惯使用其他动词风格可通过verbs覆盖默认集合。总结no-non-function-verb-prefix是 eslint-plugin-unicorn 中少有的、完全依赖 TypeScript 类型信息工作的规则它在语法层识别驼峰动词前缀在类型层判定绑定值的可调用性两者结合精准捕捉const getName Sindre这类名不副实的绑定。通过 26 个快照违规样例与 50 余个合法样例可以清晰看到其边界设计——联合类型取保守判定、交叉类型取宽松判定、声明文件与纯类型导入一律豁免。理解这些语义后无论是启用默认配置还是定制verbs/ignore都能让该规则稳定服务于命名与类型的一致性约束。【免费下载链接】eslint-plugin-unicornMore than 300 powerful ESLint rules项目地址: https://gitcode.com/GitHub_Trending/es/eslint-plugin-unicorn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考