本文へスキップ

no-extraneous-class

名前空間として使用されるクラスを禁止します。

🔒

拡張 "plugin:@typescript-eslint/strict" ESLint設定 で有効にすると、このルールが有効になります。

このルールは、静的名前空間としてのみ使用されるクラスなど、非静的メンバを持たないクラスを報告します。

オブジェクト指向プログラミング(OOP)のパラダイムから来たユーザーは、ユーティリティ関数を最上位レベルに配置する代わりに、余分なクラスにラップすることがあります。これは、JavaScriptとTypeScriptのプロジェクトでは一般的に不要です。

  • ラッパー・クラスは、構造的な改善を加えることなく、コードの認知的複雑さを増します。
    • ユーティリティ関数など、それらに配置されるものは、モジュール内にあることで既に整理されています。
    • 代替手段として、`import * as ...`を使用して、それらをすべて単一のオブジェクトに取得できます。
  • IDEは、プロパティ名を入力し始めるときに、静的クラスまたは名前空間からインポートされたプロパティについて、それほど良い提案を提供できません。
  • それらがすべてクラスにある場合、未使用の変数などのコードの静的解析はより困難になります(参照:TypeScriptにおけるデッドコード(およびデッドタイプ)の発見)。

このルールは、コンストラクタのみを持ち、フィールドを持たないクラスも報告します。これらのクラスは、一般的にスタンドアロン関数に置き換えることができます。

.eslintrc.cjs
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 class Utilities {
static util1() {
return Utilities.util3();
}

static util2() {
/* ... */
}

static util3() {
/* ... */
}
}
Playgroundで開く

モジュールのすべての構成要素を単一のオブジェクトのプロパティとして使用することを強く希望する場合は、`import * as`を使用してモジュールをインポートできます。これは「名前空間インポート」と呼ばれます。名前空間インポートは、すべてプロパティをネストした状態に保ち、モジュールから様々なプロパティの使用を開始または停止しても変更する必要がないため、場合によっては好ましいです。

ただし、名前空間インポートにはこれらの欠点があります。

  • 最新のバンドラーでのツリーシェイキングにも対応していません。
  • 各プロパティの使用前に名前空間プレフィックスが必要です。
// utilities.ts
export class Utilities {
static sayHello() {
console.log('Hello, world!');
}
}

// consumers.ts
import { Utilities } from './utilities';

Utilities.sayHello();
Playgroundで開く

変数の変更に関する注記

注意が必要なケースの1つは、変更可能な変数をエクスポートすることです。クラスのプロパティは外部から変更できますが、エクスポートされた変数は常に定数です。つまり、インポーターは割り当てられた最初の値のみを読み取ることができ、変数に書き込むことはできません。

エクスポートされた変数に書き込む必要があることは非常にまれであり、一般的にコードの臭いと考えられます。必要であれば、ゲッターとセッター関数を使用して実現できます。

export class Utilities {
static mutableCount = 1;

static incrementCount() {
Utilities.mutableCount += 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で開く

allowEmpty

allowEmptyオプションは、完全に空のクラスに対する免除を追加します。

class NoFields {
constructor() {
console.log('Hello, world!');
}
}
Playgroundで開く

allowStaticOnly

allowStaticOnlyオプションは、静的メンバのみを含むクラスに対する免除を追加します。

注意

allowStaticOnly免除は強くお勧めしません。これは、静的メンバのみで使用されるクラスを推奨しないというこのルールの主な目的と反します。

class EmptyClass {}
Playgroundで開く

allowWithDecorator

allowWithDecoratorオプションは、`@`デコレータでデコレートされたクラスに対する免除を追加します。

class Constants {
static readonly version = 42;
}
Playgroundで開く

使用しない場合

プロジェクトが最新のクラスと名前空間の慣習の前に設定されており、切り替える時間がない場合は、このルールを実際的に使用できない場合があります。このルールを完全に無効にする代わりに、特定の状況に対してESLintの無効化コメントを使用することを検討してください。

リソース