@typescript-eslint/class-methods-use-this

Require class methods to use this

Also called typescript-eslint/class-methods-use-this, typescript/class-methods-use-this

A method that never reads this doesn't need an instance, but callers still have to create one to reach it. Make it static, or move it out of the class.

The rule checks methods, getters, setters, and functions stored in instance fields. It skips constructors, static members, and abstract members.

It's the TypeScript version of class-methods-use-this and reports the same code.

With bunfig.toml you can set either name. bun lint runs this rule in TypeScript files and class-methods-use-this in JavaScript files, so nothing is reported twice. With an ESLint config, turn on only one of the two.

Configure#

Off by default. To turn it on:

bunfig.toml
[lint.rules]
"@typescript-eslint/class-methods-use-this" = "error" # or "warn"

Every option, set to its default:

bunfig.toml
[lint.rules]
"@typescript-eslint/class-methods-use-this" = ["error", {
  exceptMethods = [], # list of strings
  enforceForClassFields = true,
  ignoreOverrideMethods = false,
  # true, false or "public-fields"
  ignoreClassesThatImplementAnInterface = false,
}]

Examples#

example.ts2 problems
class Invoice {
  total = 0;

  format(amount: number) {
    return amount.toFixed(2);
  }

  round = (amount: number) => Math.round(amount);
}
example.tsNo problems
class Invoice {
  total = 0;

  static format(amount: number) {
    return amount.toFixed(2);
  }

  print() {
    return Invoice.format(this.total);
  }
}

Options#

OptionDefaultWhat it does
exceptMethods[]Names of methods to skip. Write a private method as "#name".
enforceForClassFieldstrueAlso check functions stored in instance fields, such as round above.
ignoreOverrideMethodsfalseSkip members marked override.
ignoreClassesThatImplementAnInterfacefalsetrue skips every member of a class that has an implements clause. "public-fields" still checks its private and protected members.

A subclass must keep the shape of the method it overrides, so it can't make it static:

example.tswith { "ignoreOverrideMethods": true }No problems
class Widget {
  name = "widget";
  render() {
    return this.name;
  }
}

class Spinner extends Widget {
  override render() {
    return "...";
  }
}

The same goes for a method that an interface requires. With "public-fields", render is skipped and frame is reported. With true, neither is reported.

example.tswith { "ignoreClassesThatImplementAnInterface": "public-fields" }1 problem
interface Renderable {
  render(): string;
}

class Spinner implements Renderable {
  render() {
    return "...";
  }
  private frame() {
    return 0;
  }
}