How to Define a TypeScript Getter for Private Class Properties

Use the get keyword followed by a property name and return type to expose a read-only view of a private field, preventing external modification while allowing controlled access.

When working with encapsulation in TypeScript classes, you often need to expose internal state without allowing external modification. The TypeScript getter syntax provides a clean solution for accessing private class properties while maintaining immutability from outside the class. According to the microsoft/TypeScript source code, the compiler handles these accessors by generating GetAccessorDeclaration nodes during parsing.

Understanding the TypeScript Getter Pattern

A getter (or accessor) is a special method that retrieves the value of a private backing field. By convention, private fields use an underscore prefix (e.g., _value) to distinguish them from public members.

The pattern follows three steps:

  • Declare a private field with the private access modifier
  • Define a public getter using the get keyword
  • Return the private field value from the getter body

Basic TypeScript Getter Example

class Counter {
  private _count = 0;

  public get count(): number {
    return this._count;
  }

  public increment(): void {
    this._count++;
  }
}

const c = new Counter();
c.increment();
console.log(c.count); // 1
// c._count; // Error: Property '_count' is private

Implementing Read-Only Private Properties

When you define a getter without a corresponding setter, TypeScript treats the property as read-only for external code. This prevents accidental mutation while allowing the class to modify its internal state through private methods.

class Config {
  private _apiKey = 'secret-key-123';

  public get apiKey(): string {
    return this._apiKey;
  }

  public rotateKey(): void {
    this._apiKey = `secret-${Date.now()}`;
  }
}

const cfg = new Config();
console.log(cfg.apiKey); // OK
// cfg.apiKey = 'hacked'; // Error: Cannot assign to 'apiKey' because it is a read-only property

Computed Getters for Derived Values

Getters can also calculate values dynamically based on multiple private fields, eliminating the need to store redundant data.

class Rectangle {
  private _width: number;
  private _height: number;

  constructor(w: number, h: number) {
    this._width = w;
    this._height = h;
  }

  public get area(): number {
    return this._width * this._height;
  }
}

How TypeScript Compiles Getters Internally

The TypeScript compiler processes getter declarations through specific phases in the microsoft/TypeScript repository. Understanding this pipeline helps debug complex accessor scenarios.

Parser Phase in parser.ts

When the compiler encounters a get accessor, the parser in src/compiler/parser.ts creates a GetAccessorDeclaration node. Specifically, in the parseAccessorDeclaration function (lines 57-58), the factory method distinguishes between getters and setters:

const node = kind === SyntaxKind.GetAccessor
    ? factory.createGetAccessorDeclaration(modifiers, name, parameters, type, body)
    : factory.createSetAccessorDeclaration(modifiers, name, parameters, body);

Factory and Emitter Phases

The factory.createGetAccessorDeclaration method (located in src/compiler/factory.ts) generates the AST representation. Subsequently, src/compiler/emitter.ts transforms this node into JavaScript using Object.defineProperty, creating the actual getter function in the emitted code.

Summary

  • Use the get keyword to define a TypeScript getter that exposes private fields without allowing external modification
  • Prefix private backing fields with an underscore (e.g., _value) to distinguish them from public accessors
  • Omit the set accessor to create read-only properties that prevent assignment from outside the class
  • The TypeScript compiler processes getters through GetAccessorDeclaration nodes in src/compiler/parser.ts and emits them as Object.defineProperty calls

Frequently Asked Questions

Can I define a TypeScript getter without a private backing field?

Yes, getters can compute values dynamically without storing them in a private field. For example, a get fullName() accessor could concatenate firstName and lastName properties on each access. However, for simple value storage, a private backing field remains the standard pattern.

What is the difference between a getter and a regular method in TypeScript?

A getter is invoked like a property (e.g., obj.value) rather than a method call (e.g., obj.getValue()). Internally, TypeScript compiles getters using Object.defineProperty with a get descriptor, whereas regular methods become prototype functions. Choose getters when you want property-like syntax with computed or controlled access.

Does TypeScript support getter overloading?

TypeScript does not support method overloading for getters in the traditional sense. A class can only have one getter with a specific name. However, you can use union return types or conditional logic inside the getter body to handle different scenarios based on internal state.

How does TypeScript handle getter inheritance?

Getters are inherited just like regular methods in TypeScript classes. A subclass can override a parent getter by redeclaring it with the get keyword. If the subclass needs to access the parent getter, it can use super.propertyName (without parentheses, since it's a property, not a method).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →