ESLint plugin that enforces explicit access modifiers on TypeScript class members
npm install @pegasusheavy/eslint-typescript-accessAn ESLint plugin that enforces explicit access modifiers and accessibility ordering on TypeScript class members.
- Explicit Access Modifiers — Require public, protected, or private on all class members
- Accessibility Ordering — Enforce member ordering by visibility (public → protected → private)
- Highly Configurable — Customize rules per member type (methods, properties, constructors, etc.)
- ESLint 9 Flat Config — Built for modern ESLint with first-class flat config support
``bash`
pnpm add -D @pegasusheavy/eslint-typescript-access
`bash`
npm install -D @pegasusheavy/eslint-typescript-access
`bash`
yarn add -D @pegasusheavy/eslint-typescript-access
`js
// eslint.config.js
import tsAccessPlugin from "@pegasusheavy/eslint-typescript-access";
export default [
{
plugins: {
"@pegasusheavy/typescript-access": tsAccessPlugin,
},
rules: {
"@pegasusheavy/typescript-access/explicit-member-accessibility": "error",
"@pegasusheavy/typescript-access/member-accessibility-order": "error",
},
},
];
`
The plugin provides two presets:
`js
// eslint.config.js
import tsAccessPlugin from "@pegasusheavy/eslint-typescript-access";
export default [
// Recommended: enables both rules with sensible defaults
tsAccessPlugin.configs.recommended,
// Or Strict: more explicit configuration
tsAccessPlugin.configs.strict,
];
`
Requires explicit accessibility modifiers on class properties and methods.
#### Options
`js
{
// Base accessibility requirement for all members
// "explicit" - require public/protected/private
// "no-public" - disallow explicit public (use implicit)
// "off" - disable the rule
accessibility: "explicit",
// Override for specific member types
overrides: {
constructors: "explicit",
methods: "explicit",
properties: "explicit",
parameterProperties: "explicit",
accessors: "explicit",
}
}
`
#### Examples
`typescript
// ❌ Invalid (missing accessibility)
class Example {
name: string;
getName() {
return this.name;
}
}
// ✅ Valid
class Example {
public name: string;
public getName() {
return this.name;
}
}
`
---
Enforces that class members are ordered by accessibility level.
#### Options
`js
{
// Order of accessibility levels (first = top of class)
order: ["public", "protected", "private"],
// If true, ordering is checked within each member kind separately
// (fields, methods, accessors, etc.)
groupByKind: false
}
`
#### Examples
`typescript
// ❌ Invalid (private before public)
class Example {
private secret: string;
public name: string;
}
// ✅ Valid (public → protected → private)
class Example {
public name: string;
protected id: number;
private secret: string;
}
`
#### Custom Ordering
You can customize the order to match your team's preferences:
`js`
// Private first
{
"@pegasusheavy/typescript-access/member-accessibility-order": [
"error",
{ order: ["private", "protected", "public"] }
]
}
#### Group By Kind
With groupByKind: true, ordering is checked within each member type separately, allowing you to group fields together, methods together, etc:
`typescript
// ✅ Valid with groupByKind: true
class Example {
private field1: string;
public field2: string; // OK - different group than methods below
private method1() {}
public method2() {} // Error - within methods, public should come first
}
`
`js`
{
"@pegasusheavy/typescript-access/explicit-member-accessibility": "error",
"@pegasusheavy/typescript-access/member-accessibility-order": "error"
}
`js`
{
"@pegasusheavy/typescript-access/explicit-member-accessibility": ["error", {
accessibility: "explicit",
overrides: {
constructors: "explicit",
methods: "explicit",
properties: "explicit",
parameterProperties: "explicit",
accessors: "explicit"
}
}],
"@pegasusheavy/typescript-access/member-accessibility-order": ["error", {
order: ["public", "protected", "private"],
groupByKind: false
}]
}
TypeScript defaults class members to public when no modifier is specified. This can lead to:
- Ambiguity — Is a member public intentionally or by accident?
- API Surface Creep — Private implementation details accidentally exposed
- Code Review Friction — Reviewers can't tell intent without checking context
By requiring explicit modifiers, your code becomes self-documenting:
`typescript``
// Intent is clear
class UserService {
public getCurrentUser() {} // Part of public API
protected validateUser() {} // For subclasses
private cache: Map
}
Enforcing accessibility order makes classes easier to navigate:
1. Public API First — Consumers see the interface immediately
2. Protected Next — Subclass authors find extension points
3. Private Last — Implementation details at the bottom
MIT © Pegasus Heavy Industries LLC