禁止多余的类
禁止将类用作命名空间。
在 "plugin:@typescript-eslint/strict"
中扩展 ESLint 配置 将启用此规则。
当一个类没有非静态成员时,例如用于作为静态命名空间的类,此规则会报告。
来自 OOP 范式的用户可能会将他们的实用函数包装在一个额外的类中,而不是将它们放在 ECMAScript 模块的顶层。在 JavaScript 和 TypeScript 项目中,这样做通常是不必要的。
- 包装类在不添加任何结构改进的情况下增加了代码的认知复杂度。
- 无论放在它们上面什么,例如实用函数,由于它们位于模块中,因此已经组织好了。
- 作为替代方案,您可以
import * as ...
模块以将所有内容都放在单个对象中。
- 当您开始键入属性名称时,IDE 无法为静态类或命名空间导入的属性提供更好的建议。
- 当所有变量都位于类上时,更难静态分析代码以查找未使用的变量等(参见:在 TypeScript 中查找死代码(和死类型))。
此规则还报告仅具有构造函数且没有字段的类。这些类通常可以用独立函数替换。
module.exports = {
"rules": {
"@typescript-eslint/no-extraneous-class": "error"
}
};
在游乐场中尝试此规则 ↗
示例
- ❌ 错误
- ✅ 正确
class StaticConstants {
static readonly version = 42;
static isProduction() {
return process.env.NODE_ENV === 'production';
}
}
class HelloWorldLogger {
constructor() {
console.log('Hello, world!');
}
}
在游乐场中打开export const version = 42;
export function isProduction() {
return process.env.NODE_ENV === 'production';
}
function logHelloWorld() {
console.log('Hello, world!');
}
在游乐场中打开替代方案
单独导出(推荐)
我们建议您从模块中单独导出实用程序,而不是使用静态实用程序类。
- ❌ 错误
- ✅ 正确
命名空间导入(不推荐)
如果您强烈希望将模块中的所有构造都作为单个对象的属性提供,您可以 import * as
模块。这被称为“命名空间导入”。命名空间导入有时更可取,因为它们将所有属性嵌套在一起,并且不需要在您开始或停止使用模块中的各种属性时进行更改。
但是,命名空间导入会受到以下缺点的影响
- 它们在现代打包器中也不太适合树摇。
- 它们需要在每个属性使用之前添加一个名称前缀。
- ❌ 错误
- ⚠️ 命名空间导入
- ✅ 独立导入
// utilities.ts
export class Utilities {
static sayHello() {
console.log('Hello, world!');
}
}
// consumers.ts
import { Utilities } from './utilities';
Utilities.sayHello();
在游乐场中打开// utilities.ts
export function sayHello() {
console.log('Hello, world!');
}
// consumers.ts
import * as utilities from './utilities';
utilities.sayHello();
在游乐场中打开// utilities.ts
export function sayHello() {
console.log('Hello, world!');
}
// consumers.ts
import { sayHello } from './utilities';
sayHello();
在游乐场中打开关于可变变量的说明
您需要注意的一种情况是导出可变变量。虽然类属性可以在外部被修改,但导出的变量始终是常量。这意味着导入者只能读取他们被分配的第一个值,而不能写入这些变量。
需要写入导出变量的情况非常罕见,通常被认为是代码异味。如果您确实需要它,可以使用 getter 和 setter 函数来实现。
- ❌ 错误
- ✅ 正确
选项
此规则接受以下选项。
type Options = [
{
/** Whether to allow extraneous classes that contain only a constructor. */
allowConstructorOnly?: boolean;
/** Whether to allow extraneous classes that have no body (i.e. are empty). */
allowEmpty?: boolean;
/** Whether to allow extraneous classes that only contain static members. */
allowStaticOnly?: boolean;
/** Whether to allow extraneous classes that include a decorator. */
allowWithDecorator?: boolean;
},
];
const defaultOptions: Options = [
{
allowConstructorOnly: false,
allowEmpty: false,
allowStaticOnly: false,
allowWithDecorator: false,
},
];
此规则通常禁止空的类(没有构造函数或字段)。该规则的选项分别为特定类型的类添加了豁免。
allowConstructorOnly
allowConstructorOnly
为只有构造函数而没有字段的类添加了豁免。
- ❌ 错误
- ✅ 正确
allowEmpty
allowEmpty
选项为完全为空的类添加了豁免。
- ❌ 错误
- ✅ 正确
allowStaticOnly
allowStaticOnly
选项为仅包含静态成员的类添加了豁免。
我们强烈建议不要使用 allowStaticOnly
豁免。它违背了此规则的主要目的,即阻止仅用于静态成员的类。
allowWithDecorator
allowWithDecorator
选项为用 @
装饰器装饰的类添加了豁免。
- ❌ 错误
- ✅ 正确
何时不使用它
如果您的项目是在现代类和命名空间实践出现之前创建的,并且您没有时间切换,那么您可能无法实际使用此规则。您可以考虑使用 ESLint 禁用注释 针对这些特定情况,而不是完全禁用此规则。