
ESLint no-useless-constructor 规则完全解析识别并移除冗余类构造函数【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslintno-useless-constructor是 ESLint 内置的一条 suggestion 类型规则用于标记那些删掉后类行为完全不变的多余构造函数——包括空构造函数以及仅把参数原样透传给父类的构造函数。本文以本仓库ESLint 主仓库为基准先梳理规则的使用方法与正反示例再深入 lib/rules/no-useless-constructor.js 的源码实现讲清它如何判定无用、如何处理 TypeScript 语法、以及它提供的自动修复建议最后给出禁用策略。读完本文你将能准确预判该规则的报错边界并理解其建议修复suggestion的实现细节。规则背景ES2015 的默认构造函数ES2015 为类提供了默认构造函数如果没有显式指定引擎会基于类的声明自动生成一个构造函数。对于基类默认构造函数等价于一个空构造函数对于派生类extends的类默认构造函数则等价于把收到的所有参数原样传给super()。正因如此下面这类手写的构造函数与默认行为完全等价属于冗余代码class A { constructor () { } } class B extends A { constructor (value) { super(value); } }no-useless-constructor的作用就是把这类可以安全删除的构造函数标记出来帮助开发者写出更精简的类定义。Rule Details什么算无用构造函数规则定义在 lib/rules/no-useless-constructor.js元信息位于该文件meta段第 165 行起规则类型为suggestion附带一条removeConstructor删除构造函数的修复建议且schema: []无任何可配置选项。从源码入口看规则监听MethodDefinition节点第 258-260 行对每个kind 为 constructor的方法定义调用checkForConstructor进行判定。它覆盖两类场景基类无superClass的空构造函数构造函数体语句数为 0即constructor() {}派生类中仅透传参数的构造函数构造函数体只有一条super(...)语句且参数与super实参一一对应详见下文源码实现小节。错误的代码示例会被报错/*eslint no-useless-constructor: error*/ class A { constructor () { } } class B extends A { constructor (...args) { super(...args); } }正确的代码示例不会报错/*eslint no-useless-constructor: error*/ class A { } class B { constructor () { doSomething(); } } class C extends A { constructor() { super(foo); } } class D extends A { constructor() { super(); doSomething(); } }注意其中几个关键区别class A { }不写构造函数自然没有问题class B的构造函数内调用了doSomething()有实际逻辑不视为无用class C调用super(foo)传入了固定实参而构造函数本身没有参数两者不对应删除后会改变父类收到的参数因此不报错class D在super()之后还有额外语句删除会丢失逻辑不报错。该行为在 tests/lib/rules/no-useless-constructor.js 的有效用例valid数组中有大量对应印证例如class A extends B { constructor(){ super(foo); } }—— 传入固定值合法class A extends B { constructor(foo, bar){ super(foo, bar, 1); } }—— 实参多于形参合法class A extends B { constructor(a f()) { super(...arguments); } }—— 存在默认参数合法class A extends B { constructor(){ super(); doSomething(); } }——super()后有额外逻辑合法。TypeScript 支持访问修饰符与装饰器参数该规则额外支持 TypeScript 语法。在判定时会调用hasUsefulAccessibility(node)与hasDecoratorsOrParameterProperty(node)两个辅助函数lib/rules/no-useless-constructor.js进行豁免构造函数的访问修饰符accessibility为protected或private时不算无用因为删除它会改变类的可访问性设计例如private constructor()常用于阻止外部实例化修饰符为public时仅当类没有父类时才可能被判定为无用若存在父类public constructor被保留构造函数参数带有装饰器或属于参数属性TSParameterProperty如constructor(private name: string)时不算无用因为删除构造函数会丢失装饰器初始化或参数属性声明。错误的 TypeScript 代码示例/* eslint no-useless-constructor: error */ class A { public constructor() {} }正确的 TypeScript 代码示例/* eslint no-useless-constructor: error */ class A { protected constructor() {} } class B extends A { public constructor() { super(); } } class C { constructor(decorated param) {} }测试文件 tests/lib/rules/no-useless-constructor.js 中独立的ruleTesterTypeScript区块使用typescript-eslint/parser验证了这些边界例如private constructor() {}、constructor(private name: string) {}、constructor(Foo foo) {}均为合法代码而public constructor() {}无父类则会被报错并给出删除建议。Options本规则没有配置项no-useless-constructor没有任何可配置选项源码中schema: []。你只能通过规则的开关来控制它{ rules: { no-useless-constructor: error } }或使用warn级别在集成到 CI 前先观察告警。它不属于eslint:recommended预设源码meta.docs.recommended为false需要显式开启。源码实现如何判定一个构造函数无用基类的空构造函数对没有父类的类node.parent.parent.superClass为空只要构造函数体语句数为 0 即命中lib/rules/no-useless-constructor.jssuperClass ? isRedundantSuperCall(body, ctorParams) : body.length 0派生类的透传构造函数对派生类需要构造函数体是单一super()调用且参数与实参严格对应。isRedundantSuperCall的判定链路第 47-158 行值得细读isSingleSuperCall(body)构造函数体必须只有一条语句且是CallExpression、其callee为SuperctorParams.every(isSimple)所有形参必须是Identifier或RestElement——默认参数、解构参数可能带副作用不能安全透传因此被排除满足下面任一条件即视为冗余isSpreadArguments(...)调用super(...arguments)把所有参数原样透传isPassingThrough(ctorParams, superArgs)形参与super()实参数量相同且逐位配对配对方式有两种isValidIdentifierPair同名标识符如constructor(foo){ super(foo); }isValidRestSpreadPair形参...rest与实参...rest配对如constructor(...args){ super(...args); }。一旦参数顺序错位、数量不等、传固定值或改名配对失败构造函数即被视为有用。测试中的无效用例清晰覆盖了这些命中场景例如class A extends B { constructor(foo, bar){ super(foo, bar); } }、class A extends B.C { constructor() { super(...arguments); } }、class A extends B { constructor(a, b, ...c) { super(a, b, ...c); } }。建议修复suggestion的细节规则附带一条removeConstructor建议用空字符串替换整个构造函数节点lib/rules/no-useless-constructor.js。替换并非简单删除——如果删除后与类体中的下一个成员合并会产生语法歧义它会自动补一个分号const addSemiColon astUtils.canContinueExpressionInClassBody(nextToken) astUtils.needsPrecedingSemicolon(sourceCode, node);其中canContinueExpressionInClassBody判断下一个 token 是否为[、*、in、instanceof这类会延续上一个表达式的 token见 lib/rules/utils/ast-utils.jsneedsPrecedingSemicolon进一步按 ASI自动分号插入规则判断是否需要分号隔离。测试中对此有专门验证例如class A { foo bar constructor() { } [0]() { } }删除构造函数后建议输出为在字段与方法之间插入;class A { foo bar ; [0]() { } }同理*baz() {}、in、instanceof等后续成员也会触发补分号逻辑而当后续成员是私有字段#instanceof等不会产生歧义的 token 时则直接删除并保留空行。测试文件第 232-520 行集中验证了这批边界场景。需要说明的是作为 suggestion开发者需要显式应用修复如在编辑器中使用快速修复或在--fix-type suggestion模式下处理规则本身不会在纯--fix中自动改写代码。何时不使用此规则When Not To Use It如果你不想被提醒存在多余的构造函数可以放心地关闭此规则{ rules: { no-useless-constructor: off } }典型场景包括团队约定显式书写构造函数以表达意图例如配合文档注释、装饰器或未来扩展点或项目大量使用 TypeScript 参数属性/私有构造函数等本规则豁免之外的边界用法此时关闭该规则可以避免噪音。实践小结判定核心基类看构造函数体是否为空派生类看是否单一super()调用 形参实参逐位对应或...arguments透传TypeScript 特殊处理private/protected构造函数、带装饰器或参数属性的构造函数不会被标记无配置项只能开关不能调参且不属于eslint:recommended建议修复提供removeConstructorsuggestion并在类体后续成员如[、*、in、instanceof可能造成歧义时自动补分号保证删除后语法仍然成立。如需进一步研究可继续阅读本仓库中的 规则实现、规则注册入口、完整测试用例 以及 AST 工具函数测试文件中的valid/invalid用例是最直观的规则行为规范文档。【免费下载链接】eslintFind and fix problems in your JavaScript code.项目地址: https://gitcode.com/GitHub_Trending/es/eslint创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考