eslint-plugin-unicorn 的 no-non-function-verb-prefix 规则:让 `getName`、`createPizza` 这类动词前缀命名必须指向可调用值
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),仅供参考

相关新闻

爱享素材下载器使用教程:开一个本地代理,5 分钟把视频号、抖音、小红书资源下载到本地

爱享素材下载器使用教程:开一个本地代理,5 分钟把视频号、抖音、小红书资源下载到本地

爱享素材下载器使用教程:开一个本地代理,5 分钟把视频号、抖音、小红书资源下载到本地 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_T…

2026/9/23 14:17:48 阅读更多 →
aliyunpan 阿里云盘客户端 JavaScript 插件开发指南:回调机制、内置 API 与 8 大实战场景全解析

aliyunpan 阿里云盘客户端 JavaScript 插件开发指南:回调机制、内置 API 与 8 大实战场景全解析

aliyunpan 阿里云盘客户端 JavaScript 插件开发指南:回调机制、内置 API 与 8 大实战场景全解析 【免费下载链接】aliyunpan 阿里云盘命令行客户端,支持JavaScript插件,支持同步备份功能。 项目地址: https://gitcode.com/GitHub_Trending/…

2026/9/24 4:22:33 阅读更多 →
数字电路面试题背后的工程能力解码

数字电路面试题背后的工程能力解码

简介:本资源是一份聚焦数字电子技术核心考点的高频面试题集,专为考研初试与复试、秋招春招求职者设计,系统覆盖组合逻辑与时序逻辑电路、触发器、A/D转换、存储器结构等关键模块,直击笔试与技术面常见问题。文档为单个15KB的Word文…

2026/9/23 22:15:35 阅读更多 →

最新新闻

深度学习新闻分类推荐系统:从TextCNN到个性化推荐

深度学习新闻分类推荐系统:从TextCNN到个性化推荐

简介:这份基于深度学习的新闻分类推荐系统Python实现源码,是专为课程设计与期末大作业准备的高分项目,下载后无需修改即可运行,适用于需要快速交付完整课题的高校学生。系统涵盖新闻数据预处理、文本分类模型训练、推荐逻辑展示等…

2026/9/25 0:00:41 阅读更多 →
汽车电子底层软件开发:AUTOSAR与CAN总线实战解析

汽车电子底层软件开发:AUTOSAR与CAN总线实战解析

1. 这门“汽车电子底层软件开发就业课”到底在教什么?——不是写个LED闪烁就能上岗的很多人看到“汽车电子底层软件开发就业课”这个标题,第一反应是:不就是嵌入式C语言单片机CAN通信?刷几道LeetCode、调通一个STM32 CAN收发例程&…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
CVE-2025-27591深度解析:日志组件本地权限提升漏洞与防御

CVE-2025-27591深度解析:日志组件本地权限提升漏洞与防御

CVE-2025-27591 最近在安全圈里讨论度不低,核心是 Below 这个日志处理组件在权限控制上出了问题,低权限用户有机会利用日志文件、临时目录的处理流程,把自身权限抬升到管理员甚至系统级别。很多人一听到“利用脚本”就先想到怎么打&#xff0…

2026/9/24 23:59:40 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →