ARTICLE DETAIL

资讯详情

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

ESLint no-empty-function 规则完全指南:禁止空函数、配置 allow 白名单与源码原理解析

ESLint no-empty-function 规则完全指南:禁止空函数、配置 allow 白名单与源码原理解析 ESLint no-empty-function 规则完全指南禁止空函数、配置 allow 白名单与源码原理解析【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint本篇技术指南以 ESLint 官方规则文档 docs/src/rules/no-empty-function.md 为骨架围绕「如何禁止代码中出现空函数」这一代码规范问题展开。你将掌握该规则的 14 种函数分类方式、allow选项的精细化配置方法、含注释空函数的处理策略以及它在 JavaScript 与 TypeScript私有构造器、装饰器、override 方法等场景下的完整用法同时结合 lib/rules/no-empty-function.js 的实现与 tests/lib/rules/no-empty-function.js 的测试用例深入理解规则底层是如何判定与报告问题的。为什么禁止空函数空函数会降低代码的可读性读者看到function foo() {}时需要猜测这究竟是「刻意留白」还是「忘了实现」。因此在空函数体中写上清晰的注释是一种良好实践function foo() { // do nothing. }尤其需要注意的是箭头函数的空块很容易让开发者产生困惑——它和空对象字面量长得非常相似list.map(() {}); // 这是一个代码块block会返回 undefined。 list.map(() ({})); // 这是一个空对象empty object。两者只有一个括号之差但语义完全不同。no-empty-function规则正是为了消除这类「空的、无注释的函数体」让空函数要么被显式注释说明要么被allow选项明确豁免。Rule Details本规则的目标是消除空函数。一个函数只要包含注释就不会被视作问题。从源码看判定逻辑位于 lib/rules/no-empty-function.js 的reportIfEmpty函数被标记为违规需同时满足三个条件——该函数未被allow选项豁免isAllowedEmptyFunction返回 false函数体是空的BlockStatementnode.body.body.length 0函数体内没有任何注释innerComments.length 0。因此只要函数体内存在任意一行注释如// do nothing.或/* empty */规则就不会报告。不正确的代码示例::: incorrect/*eslint no-empty-function: error*/ function foo() {} const bar function() {}; const bar1 () {}; function* baz() {} const bar2 function*() {}; const obj { foo: function() {}, foo: function*() {}, foo() {}, *foo() {}, get foo() {}, set foo(value) {} }; class A { constructor() {} foo() {} *foo() {} get foo() {} set foo(value) {} static foo() {} static *foo() {} static get foo() {} static set foo(value) {} }:::可以看到规则覆盖了普通函数声明、函数表达式、箭头函数、生成器函数以及对象字面量中的方法简写、生成器方法、getter、setter还有类中的构造器、实例/静态方法、静态生成器方法、静态 getter/setter 等所有函数形态。正确的代码示例::: correct/*eslint no-empty-function: error*/ function foo() { // do nothing. } const baz function() { // any clear comments. }; const baz1 () { bar(); }; function* foobar() { // do nothing. } const baz2 function*() { // do nothing. }; const obj { foo: function() { // do nothing. }, foo: function*() { // do nothing. }, foo() { // do nothing. }, *foo() { // do nothing. }, get foo() { // do nothing. }, set foo(value) { // do nothing. } }; class A { constructor() { // do nothing. } foo() { // do nothing. } *foo() { // do nothing. } get foo() { // do nothing. } set foo(value) { // do nothing. } static foo() { // do nothing. } static *foo() { // do nothing. } static get foo() { // do nothing. } static set foo(value) { // do nothing. } }:::注意一个细节即使函数体内有语句如baz1中调用了bar()也自然不算空函数而 getter/setter、构造器等无论是否包含语句只要函数体为空且无注释都会被报告。Options本规则只有一个选项用于允许特定种类的函数保持为空allowstring[]— 允许为空的函数种类列表列表项为下列字符串之一默认值为空数组[]即默认所有空函数都会被报告。functions— 普通函数。arrowFunctions— 箭头函数。generatorFunctions— 生成器函数。methods— 类方法和对象字面量的方法简写。generatorMethods— 带生成器的类方法和对象字面量的方法简写。getters— Getter。setters— Setter。constructors— 类构造器。asyncFunctions— 异步函数。asyncMethods— 异步类方法和对象字面量的方法简写。privateConstructors— 私有类构造器。仅 TypeScriptprotectedConstructors— 受保护的类构造器。仅 TypeScriptdecoratedFunctions— 带装饰器的类方法。仅 TypeScriptoverrideMethods— 使用override关键字的方法。仅 TypeScript在 lib/rules/no-empty-function.js 中这 14 个取值被定义为ALLOW_OPTIONS常量通过Object.freeze冻结同时规则 schema 声明了allow数组的元素必须是这些枚举值之一、且不能重复uniqueItems: true配置了非法值会在配置校验阶段直接报错。在 flat config 模式下配置方式如下// eslint.config.js export default [ { rules: { no-empty-function: [error, { allow: [constructors, arrowFunctions] }] } } ];allow: functions允许普通函数函数声明、函数表达式、对象字面量中以function形式书写的属性值为空。::: correct/*eslint no-empty-function: [error, { allow: [functions] }]*/ function foo() {} const bar function() {}; const obj { foo: function() {} };:::注意此选项下对象字面量中的foo() {}方法简写、类方法等仍然会被报告因为它们属于methods而非functions。从源码的getKindlib/rules/no-empty-function.js可以看出判定依据是 AST 父节点类型父节点为Property且method为真时归为methods否则归为functions。allow: arrowFunctions允许箭头函数为空。::: correct/*eslint no-empty-function: [error, { allow: [arrowFunctions] }]*/ const foo () {};:::源码中箭头函数是特殊分支getKind只要遇到ArrowFunctionExpression节点就直接返回arrowFunctions不再检查父节点因为箭头函数不可能同时是方法、getter 或构造器。allow: generatorFunctions允许生成器函数函数声明、函数表达式、对象字面量中的function*属性值为空。::: correct/*eslint no-empty-function: [error, { allow: [generatorFunctions] }]*/ function* foo() {} const bar function*() {}; const obj { foo: function*() {} };:::allow: methods允许类方法和对象字面量的方法简写为空含静态方法。::: correct/*eslint no-empty-function: [error, { allow: [methods] }]*/ const obj { foo() {} }; class A { foo() {} static foo() {} }:::allow: generatorMethods允许带生成器的类方法和对象字面量的方法简写为空。::: correct/*eslint no-empty-function: [error, { allow: [generatorMethods] }]*/ const obj { *foo() {} }; class A { *foo() {} static *foo() {} }:::allow: getters允许 getter 为空。::: correct/*eslint no-empty-function: [error, { allow: [getters] }]*/ const obj { get foo() {} }; class A { get foo() {} static get foo() {} }:::allow: setters允许 setter 为空。::: correct/*eslint no-empty-function: [error, { allow: [setters] }]*/ const obj { set foo(value) {} }; class A { set foo(value) {} static set foo(value) {} }:::allow: constructors允许类构造器为空。::: correct/*eslint no-empty-function: [error, { allow: [constructors] }]*/ class A { constructor() {} }:::allow: asyncFunctions允许异步函数为空。::: correct/*eslint no-empty-function: [error, { allow: [asyncFunctions] }]*/ async function a(){}:::allow: asyncMethods允许异步类方法和对象字面量的方法简写为空。::: correct/*eslint no-empty-function: [error, { allow: [asyncMethods] }]*/ const obj { async foo() {} }; class A { async foo() {} static async foo() {} }:::allow: privateConstructors允许私有类构造器为空TypeScript 专用。测试覆盖见 tests/lib/rules/no-empty-function.js源码在 lib/rules/no-empty-function.js 中通过检查node.parent.accessibility private实现。::: correct/*eslint no-empty-function: [error, { allow: [privateConstructors] }]*/ class A { private constructor() {} }:::allow: protectedConstructors允许受保护的类构造器为空TypeScript 专用。::: correct/*eslint no-empty-function: [error, { allow: [protectedConstructors] }]*/ class A { protected constructor() {} }:::allow: decoratedFunctions允许带装饰器的类方法为空TypeScript 专用。::: correct/*eslint no-empty-function: [error, { allow: [decoratedFunctions] }]*/ class A { decorator foo() {} }:::allow: overrideMethods允许使用override关键字的方法为空TypeScript 专用。::: correct/*eslint no-empty-function: [error, { allow: [overrideMethods] }]*/ abstract class Base { abstract method(): void; } class Derived extends Base { override method() {} }:::源码层面的判定逻辑与边界情况函数种类kind是如何计算出来的规则核心是 lib/rules/no-empty-function.js 中的getKind(node)函数。它对三类 AST 节点ArrowFunctionExpression、FunctionDeclaration、FunctionExpression进行分类箭头函数直接归为arrowFunctions依据父节点类型与属性判断基础种类父节点是Property时根据kind为get/set返回getters/setters否则根据method区分methods与functions父节点是MethodDefinition时同理且kind为constructor时返回constructors其余情况均为functions再根据node.generator与node.async追加前缀拼出generatorFunctions、asyncMethods等复合种类。这就是为什么「对象字面量的foo: function() {}」与「foo() {}方法简写」会被区分对待——前者的Property.method为 false后者为 true。构造器的特殊豁免参数属性在 lib/rules/no-empty-function.js 中还有一个特殊处理isParameterPropertiesConstructor如果 TypeScript 构造器的参数带有public/private/protected/readonly修饰符即参数属性即使构造器体为空也不会被报告。这是因为此时构造器并非真正「空」——参数属性会在编译期生成赋值语句。测试用例 tests/lib/rules/no-empty-function.js 覆盖了这四种情况class A { constructor(public param: string) {} } class A { constructor(private param: string) {} } class A { constructor(protected param: string) {} } class A { constructor(readonly param: string) {} }装饰器与 override 的组合判定isAllowedEmptyFunctionlib/rules/no-empty-function.js对getters/setters/各类methods还会做二次检查若父节点带装饰器且配置了decoratedFunctions或父节点带override且配置了overrideMethods则同样放行。测试中覆盖了大量组合场景例如「同时带装饰器与 override 的方法」需要同时配置三者才会放行tests/lib/rules/no-empty-function.js。错误消息与自动修复建议规则在 meta 中声明了hasSuggestions: truelib/rules/no-empty-function.js并注册了两条消息unexpectedUnexpected empty {{name}}.suggestCommentAdd comment inside empty {{name}}.其中name由工具函数getFunctionNameWithKindlib/rules/utils/ast-utils.js生成会拼出function foo、method foo、static getter foo、async function a等可读名称。当函数体为空时规则会报告错误并附带一个可自动应用的修复建议在空花括号内插入注释/* empty */。修复实现见 lib/rules/no-empty-function.js通过替换函数体range[0]1到range[1]-1之间的空区间实现。对应测试断言了修复输出例如function foo() {}会被修复为function foo() { /* empty */ }tests/lib/rules/no-empty-function.js。需要说明的是ESLint 的建议suggestion修复默认不会在--fix时自动应用需要通过编辑器或--fix-type suggestion场景下手动接受建议。与 no-empty 规则的关系该规则的related_rules元数据指向no-empty见 docs/src/rules/no-empty-function.md 的 front matter 与 docs/src/_data/rules_meta.json。两者的区别在于no-empty禁止的是所有「空的块语句」包括空的if、for、while、try、switch等且这些场景下空块中的注释通常不能豁免——no-empty要求块内必须有注释或allowEmptyCatch等特殊配置而no-empty-function只针对「空的函数体」。生产项目中两者可以同时开启前者管块语句后者管函数体。规则元数据速览依据 docs/src/_data/rules_meta.json该规则的元数据为元数据字段值规则类型typesuggestion推荐开启recommendedfalse支持语言dialectsJavaScript、TypeScript默认选项defaultOptions[{ allow: [] }]支持建议修复hasSuggestionstrue规则类型为suggestion意味着它提出的是风格与可维护性建议而非检测到明确的程序 bug因此在eslint:recommended中默认不开启需要按需手动配置。何时不使用本规则When Not To Use It如果你不希望收到关于空函数的提示那么可以安全地禁用此规则。典型场景包括项目中大量使用「占位/桩函数」如 mock、测试替身、事件处理器占位且团队认为空函数体本身语义清晰与第三方代码风格或框架要求冲突例如某些基类要求子类实现空方法以供覆写已有其他机制如no-empty加allowEmptyCatch、代码评审规范约束空代码块无需重复提示。禁用方式flat config// eslint.config.js export default [ { rules: { no-empty-function: off } } ];总结no-empty-function是 ESLint 中面向代码可读性的建议型规则它默认报告所有函数体为空且无注释的函数并通过allow选项支持对普通函数、箭头函数、生成器、方法、getter/setter、构造器、异步函数等 14 种函数形态进行细粒度豁免同时针对 TypeScript 提供了私有/受保护构造器、装饰器方法、override方法以及构造器参数属性的特殊处理。其实现lib/rules/no-empty-function.js通过 AST 父节点判定函数种类、以「空块 无注释」作为报告条件并提供插入/* empty */注释的建议修复配合 tests/lib/rules/no-empty-function.js 中超过千行的用例保证了 JS/TS 各语法形态下的行为一致。配置该规则时建议结合团队代码习惯明确「哪些空函数可以存在」用注释说明空函数的意图让「留白」从猜疑变成约定。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表