no-extraneous-class
名前空間として使用されるクラスを禁止します。
拡張 "plugin:@typescript-eslint/strict"
を ESLint設定 で有効にすると、このルールが有効になります。
このルールは、静的名前空間としてのみ使用されるクラスなど、非静的メンバを持たないクラスを報告します。
オブジェクト指向プログラミング(OOP)のパラダイムから来たユーザーは、ユーティリティ関数を最上位レベルに配置する代わりに、余分なクラスにラップすることがあります。これは、JavaScriptとTypeScriptのプロジェクトでは一般的に不要です。
- ラッパー・クラスは、構造的な改善を加えることなく、コードの認知的複雑さを増します。
- ユーティリティ関数など、それらに配置されるものは、モジュール内にあることで既に整理されています。
- 代替手段として、`import * as ...`を使用して、それらをすべて単一のオブジェクトに取得できます。
- IDEは、プロパティ名を入力し始めるときに、静的クラスまたは名前空間からインポートされたプロパティについて、それほど良い提案を提供できません。
- それらがすべてクラスにある場合、未使用の変数などのコードの静的解析はより困難になります(参照:TypeScriptにおけるデッドコード(およびデッドタイプ)の発見)。
このルールは、コンストラクタのみを持ち、フィールドを持たないクラスも報告します。これらのクラスは、一般的にスタンドアロン関数に置き換えることができます。
module.exports = {
"rules": {
"@typescript-eslint/no-extraneous-class": "error"
}
};
Playgroundでこのルールを試してみてください ↗
例
- ❌ 正しくない
- ✅ 正しい
class StaticConstants {
static readonly version = 42;
static isProduction() {
return process.env.NODE_ENV === 'production';
}
}
class HelloWorldLogger {
constructor() {
console.log('Hello, world!');
}
}
Playgroundで開くexport const version = 42;
export function isProduction() {
return process.env.NODE_ENV === 'production';
}
function logHelloWorld() {
console.log('Hello, world!');
}
Playgroundで開く代替案
個々のエクスポート(推奨)
静的ユーティリティクラスを使用する代わりに、モジュールからユーティリティを個別にエクスポートすることをお勧めします。
- ❌ 正しくない
- ✅ 正しい
export class Utilities {
static util1() {
return Utilities.util3();
}
static util2() {
/* ... */
}
static util3() {
/* ... */
}
}
Playgroundで開くexport function util1() {
return util3();
}
export function util2() {
/* ... */
}
export function util3() {
/* ... */
}
Playgroundで開く名前空間インポート(推奨しない)
モジュールのすべての構成要素を単一のオブジェクトのプロパティとして使用することを強く希望する場合は、`import * as`を使用してモジュールをインポートできます。これは「名前空間インポート」と呼ばれます。名前空間インポートは、すべてプロパティをネストした状態に保ち、モジュールから様々なプロパティの使用を開始または停止しても変更する必要がないため、場合によっては好ましいです。
ただし、名前空間インポートにはこれらの欠点があります。
- 最新のバンドラーでのツリーシェイキングにも対応していません。
- 各プロパティの使用前に名前空間プレフィックスが必要です。
- ❌ 正しくない
- ⚠️ 名前空間インポート
- ✅ スタンドアロンインポート
// utilities.ts
export class Utilities {
static sayHello() {
console.log('Hello, world!');
}
}
// consumers.ts
import { Utilities } from './utilities';
Utilities.sayHello();
Playgroundで開く// utilities.ts
export function sayHello() {
console.log('Hello, world!');
}
// consumers.ts
import * as utilities from './utilities';
utilities.sayHello();
Playgroundで開く// utilities.ts
export function sayHello() {
console.log('Hello, world!');
}
// consumers.ts
import { sayHello } from './utilities';
sayHello();
Playgroundで開く変数の変更に関する注記
注意が必要なケースの1つは、変更可能な変数をエクスポートすることです。クラスのプロパティは外部から変更できますが、エクスポートされた変数は常に定数です。つまり、インポーターは割り当てられた最初の値のみを読み取ることができ、変数に書き込むことはできません。
エクスポートされた変数に書き込む必要があることは非常にまれであり、一般的にコードの臭いと考えられます。必要であれば、ゲッターとセッター関数を使用して実現できます。
- ❌ 正しくない
- ✅ 正しい
export class Utilities {
static mutableCount = 1;
static incrementCount() {
Utilities.mutableCount += 1;
}
}
Playgroundで開くlet mutableCount = 1;
export function getMutableCount() {
return mutableField;
}
export function incrementCount() {
mutableField += 1;
}
Playgroundで開くオプション
このルールは、次のオプションを受け入れます。
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
は、コンストラクタのみを持ち、フィールドを持たないクラスに対する免除を追加します。
- ❌ 正しくない
- ✅ 正しい
class NoFields {}
Playgroundで開くclass NoFields {
constructor() {
console.log('Hello, world!');
}
}
Playgroundで開くallowEmpty
allowEmpty
オプションは、完全に空のクラスに対する免除を追加します。
- ❌ 正しくない
- ✅ 正しい
class NoFields {
constructor() {
console.log('Hello, world!');
}
}
Playgroundで開くclass NoFields {}
Playgroundで開くallowStaticOnly
allowStaticOnly
オプションは、静的メンバのみを含むクラスに対する免除を追加します。
allowStaticOnly
免除は強くお勧めしません。これは、静的メンバのみで使用されるクラスを推奨しないというこのルールの主な目的と反します。
- ❌ 正しくない
- ✅ 正しい
class EmptyClass {}
Playgroundで開くclass NotEmptyClass {
static version = 42;
}
Playgroundで開くallowWithDecorator
allowWithDecorator
オプションは、`@`デコレータでデコレートされたクラスに対する免除を追加します。
- ❌ 正しくない
- ✅ 正しい
class Constants {
static readonly version = 42;
}
Playgroundで開く@logOnRead()
class Constants {
static readonly version = 42;
}
Playgroundで開く使用しない場合
プロジェクトが最新のクラスと名前空間の慣習の前に設定されており、切り替える時間がない場合は、このルールを実際的に使用できない場合があります。このルールを完全に無効にする代わりに、特定の状況に対してESLintの無効化コメントを使用することを検討してください。