@typescript-eslint/no-extraneous-class

Disallow classes that are empty, only static, or only a constructor

Also called typescript-eslint/no-extraneous-class, typescript/no-extraneous-class

A class with only static members is a group of functions and constants, not something you make instances of. Every call needs the MathUtils. prefix, and a bundler keeps the whole class even if you use one function. Export the functions and constants from the module instead. A class with only a constructor is a function, and an empty class does nothing.

A class that extends another class isn't reported. Neither is a class with a constructor that declares properties in its parameters, such as constructor(public x: number) {}.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"@typescript-eslint/no-extraneous-class" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"@typescript-eslint/no-extraneous-class" = ["error", {
  allowConstructorOnly = false,
  allowEmpty = false,
  allowStaticOnly = false,
  allowWithDecorator = false,
}]

Examples#

example.ts1 problem
export class MathUtils {
  static readonly TAU = Math.PI * 2;

  static clamp(value: number, min: number, max: number) {
    return Math.min(Math.max(value, min), max);
  }
}
example.ts2 problems
class Placeholder {}

class Startup {
  constructor() {
    console.log("started");
  }
}
example.tsNo problems
export const TAU = Math.PI * 2;

export function clamp(value: number, min: number, max: number) {
  return Math.min(Math.max(value, min), max);
}
example.tsNo problems
class Counter {
  static instances = 0;
  count = 0;
}

class NotFoundError extends Error {}

class Point {
  constructor(public x: number, public y: number) {}
}

Options#

OptionDefaultWhat it does
allowConstructorOnlyfalseAllow a class that has only a constructor.
allowEmptyfalseAllow a class with no members.
allowStaticOnlyfalseAllow a class that has only static members.
allowWithDecoratorfalseAllow any class that has a decorator.

Some frameworks configure a class through its decorator, and the body stays empty:

example.tswith { "allowWithDecorator": true }No problems
import { Module } from "./framework";

@Module({ providers: [] })
export class AppModule {}
example.tswith { "allowStaticOnly": true }No problems
export class Env {
  static readonly isProduction = process.env.NODE_ENV === "production";
}