SyntaxStudy
Sign Up
TypeScript Getters, Setters, and the Singleton Pattern
TypeScript Beginner 1 min read

Getters, Setters, and the Singleton Pattern

TypeScript supports getter and setter accessors on classes using the get and set keywords, mirroring the ECMAScript specification. Getters compute a value from internal state and present it as a property, while setters validate and assign incoming values before storing them. The accessor pair must have compatible types — the getter return type must be assignable to the setter parameter type. Access modifiers can be applied to getters and setters independently. You can have a public getter with a protected or private setter, creating a property that is readable by all but only writable internally. This is a clean way to expose computed or validated state without allowing arbitrary external mutation. Design patterns like Singleton, which ensures only one instance of a class exists, are easy to implement in TypeScript using private constructors and static factory methods. The private constructor prevents instantiation with new from outside the class. TypeScript enforces this at compile time, making the pattern impossible to circumvent accidentally.
Example
// Getters and setters
class Temperature {
    private _celsius: number;

    constructor(celsius: number) {
        this._celsius = celsius;
    }

    get celsius(): number { return this._celsius; }
    set celsius(value: number) {
        if (value < -273.15) throw new RangeError("Below absolute zero");
        this._celsius = value;
    }

    get fahrenheit(): number { return this._celsius * 9 / 5 + 32; }
    set fahrenheit(value: number) { this.celsius = (value - 32) * 5 / 9; }

    get kelvin(): number { return this._celsius + 273.15; }
}

const t = new Temperature(100);
console.log(t.fahrenheit); // 212
t.fahrenheit = 32;
console.log(t.celsius);    // 0

// Singleton pattern with private constructor
class AppConfig {
    private static instance: AppConfig | null = null;

    private constructor(
        public readonly apiUrl: string,
        public readonly debug: boolean,
    ) {}

    static getInstance(): AppConfig {
        if (!AppConfig.instance) {
            AppConfig.instance = new AppConfig(
                process.env["API_URL"] ?? "https://api.example.com",
                process.env["NODE_ENV"] !== "production",
            );
        }
        return AppConfig.instance;
    }
}

const cfg1 = AppConfig.getInstance();
const cfg2 = AppConfig.getInstance();
console.log(cfg1 === cfg2); // true — same instance