Skip to content

Private readonly members

  • Modifiers: private, readonly
  • Allowed: UPPER_CASE, camelCase
  • Leading underscore: forbidden

Why This Rule

Private readonly members are immutable internals. They can represent either constants or configuration:

  • UPPER_CASE: For true constants set at compile time (MAX_RETRIES, DEFAULT_TIMEOUT)
  • camelCase: For values initialized in the constructor or set once (apiKey, userId)

When to use each:

ts
class ApiClient {
  // True constant - known at compile time
  private readonly MAX_RETRIES = 3; // WHY: UPPER_CASE for a true compile-time constant

  // Configuration value - set in constructor
  private readonly apiKey: string; // WHY: camelCase for constructor-provided readonly value

  constructor(apiKey: string) {
    this.apiKey = apiKey;
  }
}

No underscore: The private keyword already signals encapsulation. The underscore adds no value.

Why allow both formats:

Not all readonly values are constants. Some are set once during initialization and never change, but they're instance-specific configuration rather than universal constants. Using camelCase for these feels more natural than SHOUTING_CASE.

References:

✅ Good

ts
class Example {
  private readonly MAX_RETRIES = 3; // WHY: UPPER_CASE for compile-time constant
  private readonly maxRetries = 3; // WHY: camelCase for instance-specific readonly value
}

❌ Bad

ts
class Example {
  private readonly _maxRetries = 3; // WHY: leading underscore forbidden
  private readonly MaxRetries = 3; // WHY: PascalCase misleading for a property
}