Skip to content

Latest commit

 

History

History
350 lines (286 loc) · 8.47 KB

explicit-member-accessibility.md

File metadata and controls

350 lines (286 loc) · 8.47 KB
description
Require explicit accessibility modifiers on class properties and methods.

🛑 This file is source code, not the primary documentation location! 🛑

See https://typescript-eslint.io/rules/explicit-member-accessibility for documentation.

Leaving off accessibility modifier and making everything public can make your interface hard to use by others. If you make all internal pieces private or protected, your interface will be easier to use.

Rule Details

This rule aims to make code more readable and explicit about who can use which properties.

Options

type AccessibilityLevel =
  | 'explicit' // require an accessor (including public)
  | 'no-public' // don't require public
  | 'off'; // don't check

type Options = {
  accessibility?: AccessibilityLevel;
  ignoredMethodNames?: string[];
  overrides?: {
    accessors?: AccessibilityLevel;
    constructors?: AccessibilityLevel;
    methods?: AccessibilityLevel;
    properties?: AccessibilityLevel;
    parameterProperties?: AccessibilityLevel;
  };
};

const defaultOptions: Options = {
  accessibility: 'explicit',
};

Configuring in a mixed JS/TS codebase

If you are working on a codebase within which you lint non-TypeScript code (i.e. .js/.mjs/.cjs/.jsx), you should ensure that you should use ESLint overrides to only enable the rule on .ts/.mts/.cts/.tsx files. If you don't, then you will get unfixable lint errors reported within .js/.mjs/.cjs/.jsx files.

{
  "rules": {
    // disable the rule for all files
    "@typescript-eslint/explicit-member-accessibility": "off"
  },
  "overrides": [
    {
      // enable the rule specifically for TypeScript files
      "files": ["*.ts", "*.mts", "*.cts", "*.tsx"],
      "rules": {
        "@typescript-eslint/explicit-member-accessibility": ["error"]
      }
    }
  ]
}

accessibility

This rule in its default state requires no configuration and will enforce that every class member has an accessibility modifier. If you would like to allow for some implicit public members then you have the following options:

{
  accessibility: 'explicit',
  overrides: {
    accessors: 'explicit',
    constructors: 'no-public',
    methods: 'explicit',
    properties: 'off',
    parameterProperties: 'explicit'
  }
}

Note the above is an example of a possible configuration you could use - it is not the default configuration.

The following patterns are considered incorrect code if no options are provided:

class Animal {
  constructor(name) {
    // No accessibility modifier
    this.animalName = name;
  }
  animalName: string; // No accessibility modifier
  get name(): string {
    // No accessibility modifier
    return this.animalName;
  }
  set name(value: string) {
    // No accessibility modifier
    this.animalName = value;
  }
  walk() {
    // method
  }
}

The following patterns are considered correct with the default options { accessibility: 'explicit' }:

class Animal {
  public constructor(public breed, name) {
    // Parameter property and constructor
    this.animalName = name;
  }
  private animalName: string; // Property
  get name(): string {
    // get accessor
    return this.animalName;
  }
  set name(value: string) {
    // set accessor
    this.animalName = value;
  }
  public walk() {
    // method
  }
}

The following patterns are considered incorrect with the accessibility set to no-public [{ accessibility: 'no-public' }]:

class Animal {
  public constructor(public breed, name) {
    // Parameter property and constructor
    this.animalName = name;
  }
  public animalName: string; // Property
  public get name(): string {
    // get accessor
    return this.animalName;
  }
  public set name(value: string) {
    // set accessor
    this.animalName = value;
  }
  public walk() {
    // method
  }
}

The following patterns are considered correct with the accessibility set to no-public [{ accessibility: 'no-public' }]:

class Animal {
  constructor(protected breed, name) {
    // Parameter property and constructor
    this.name = name;
  }
  private animalName: string; // Property
  get name(): string {
    // get accessor
    return this.animalName;
  }
  private set name(value: string) {
    // set accessor
    this.animalName = value;
  }
  protected walk() {
    // method
  }
}

Overrides

There are three ways in which an override can be used.

  • To disallow the use of public on a given member.
  • To enforce explicit member accessibility when the root has allowed implicit public accessibility
  • To disable any checks on given member type

Disallow the use of public on a given member

e.g. [ { overrides: { constructors: 'no-public' } } ]

The following patterns are considered incorrect with the example override

class Animal {
  public constructor(protected animalName) {}
  public get name() {
    return this.animalName;
  }
}

The following patterns are considered correct with the example override

class Animal {
  constructor(protected animalName) {}
  public get name() {
    return this.animalName;
  }
}

Require explicit accessibility for a given member

e.g. [ { accessibility: 'no-public', overrides: { properties: 'explicit' } } ]

The following patterns are considered incorrect with the example override

class Animal {
  constructor(protected animalName) {}
  get name() {
    return this.animalName;
  }
  protected set name(value: string) {
    this.animalName = value;
  }
  legs: number;
  private hasFleas: boolean;
}

The following patterns are considered correct with the example override

class Animal {
  constructor(protected animalName) {}
  get name() {
    return this.animalName;
  }
  protected set name(value: string) {
    this.animalName = value;
  }
  public legs: number;
  private hasFleas: boolean;
}

e.g. [ { accessibility: 'off', overrides: { parameterProperties: 'explicit' } } ]

The following code is considered incorrect with the example override

class Animal {
  constructor(readonly animalName: string) {}
}

The following code patterns are considered correct with the example override

class Animal {
  constructor(public readonly animalName: string) {}
}

class Animal {
  constructor(public animalName: string) {}
}

class Animal {
  constructor(animalName: string) {}
}

e.g. [ { accessibility: 'off', overrides: { parameterProperties: 'no-public' } } ]

The following code is considered incorrect with the example override

class Animal {
  constructor(public readonly animalName: string) {}
}

The following code is considered correct with the example override

class Animal {
  constructor(public animalName: string) {}
}

Disable any checks on given member type

e.g. [{ overrides: { accessors : 'off' } } ]

As no checks on the overridden member type are performed all permutations of visibility are permitted for that member type

The follow pattern is considered incorrect for the given configuration

class Animal {
  constructor(protected animalName) {}
  public get name() {
    return this.animalName;
  }
  get legs() {
    return this.legCount;
  }
}

The following patterns are considered correct with the example override

class Animal {
  public constructor(protected animalName) {}
  public get name() {
    return this.animalName;
  }
  get legs() {
    return this.legCount;
  }
}

Except specific methods

If you want to ignore some specific methods, you can do it by specifying method names. Note that this option does not care for the context, and will ignore every method with these names, which could lead to it missing some cases. You should use this sparingly. e.g. [ { ignoredMethodNames: ['specificMethod', 'whateverMethod'] } ]

class Animal {
  get specificMethod() {
    console.log('No error because you specified this method on option');
  }
  get whateverMethod() {
    console.log('No error because you specified this method on option');
  }
  public get otherMethod() {
    console.log('This method comply with this rule');
  }
}

When Not To Use It

If you think defaulting to public is a good default, then you should consider using the no-public setting. If you want to mix implicit and explicit public members then disable this rule.

Further Reading