new. In contrast, Static Members belong to the Class Constructor Function itself. They allow defining shared utility methods, global constants, and singletons.1. Instance Members vs Static Members#
To understand static members, visualize where properties reside in memory:
- Instance Members: Copied or linked to every object created via
new MyClass(). - Static Members: Stored once on the
MyClassconstructor object itself.
class MathOperations {
// Static Constant
public static readonly PI: number = 3.14159265359;
// Static Utility Method
public static calculateCircleArea(radius: number): number {
return MathOperations.PI * (radius ** 2);
}
}
// 🟢 WORKED: Accessing static members directly on the class constructor!
console.log(MathOperations.PI); // 3.14159265359
console.log(MathOperations.calculateCircleArea(10)); // ~314.159
// ❌ Compiler Error: Property 'PI' does not exist on type 'MathOperations' (instance).
// const inst = new MathOperations();
// console.log(inst.PI);
2. Static Access Modifiers (public static, private static)#
Just like instance members, static members can be combined with public, private, and protected access modifiers:
class ApplicationConfig {
// Public static constant
public static readonly APP_NAME = "E-Commerce Core";
// Private static storage
private static activeConnections: number = 0;
// Private static helper method
private static logConnectionChange() {
console.log(`[CONFIG]: Active connections updated to ${ApplicationConfig.activeConnections}`);
}
public static trackNewConnection() {
ApplicationConfig.activeConnections++;
ApplicationConfig.logConnectionChange();
}
public static getActiveConnections(): number {
return ApplicationConfig.activeConnections;
}
}
ApplicationConfig.trackNewConnection(); // "[CONFIG]: Active connections updated to 1"
// ❌ Compiler Error: Property 'activeConnections' is private and only accessible within class 'ApplicationConfig'.
// console.log(ApplicationConfig.activeConnections);
3. Static Initialization Blocks (static {})#
Introduced in ECMAScript 2022 (and TypeScript 4.4), Static Blocks allow you to write complex, multi-statement initialization logic for static fields, complete with try/catch error handling and private field access.
class EnvironmentRegistry {
public static readonly API_ENDPOINT: string;
public static readonly IS_PRODUCTION: boolean;
// Static Initialization Block (Runs ONCE when the class is loaded into memory)
static {
try {
const rawEnv = process.env.NODE_ENV || "development";
EnvironmentRegistry.IS_PRODUCTION = rawEnv === "production";
if (EnvironmentRegistry.IS_PRODUCTION) {
EnvironmentRegistry.API_ENDPOINT = "https://api.acme.com/v1";
} else {
EnvironmentRegistry.API_ENDPOINT = "http://localhost:8080/v1";
}
console.log(`[Registry]: Environment initialized as ${rawEnv}`);
} catch (err) {
EnvironmentRegistry.API_ENDPOINT = "http://fallback.local";
EnvironmentRegistry.IS_PRODUCTION = false;
}
}
}
console.log(EnvironmentRegistry.API_ENDPOINT);Why use static {} blocks?#
Static blocks can access private static fields from within the class body, allowing complex setup logic that standard inline property initializers cannot perform.
4. The Singleton Design Pattern#
The Singleton Pattern restricts the instantiation of a class to one single, shared instance across the entire application runtime. It is frequently used for database pools, logger services, and state stores.
How to Build a Singleton in TypeScript:#
- Make the
constructor()privateso external callers cannot invokenew DatabaseConnection(). - Store the single instance in a
private staticvariable. - Provide a
public static getInstance()method to lazily construct and return the instance.
class DatabasePoolManager {
// 1. Private static variable holding the single instance
private static instance: DatabasePoolManager | null = null;
private connectionId: string;
// 2. PRIVATE CONSTRUCTOR stops external callers from using 'new'!
private constructor() {
this.connectionId = `conn_${Math.random().toString(36).substring(2, 9)}`;
console.log(`[DatabasePool]: Opened pool with ID: ${this.connectionId}`);
}
// 3. Public static getter for lazy initialization
public static getInstance(): DatabasePoolManager {
if (DatabasePoolManager.instance === null) {
DatabasePoolManager.instance = new DatabasePoolManager();
}
return DatabasePoolManager.instance;
}
public query(sql: string) {
console.log(`Executing SQL on pool ${this.connectionId}: ${sql}`);
}
}
// ❌ Compiler Error: Constructor of class 'DatabasePoolManager' is private and only accessible within the class declaration.
// const badDb = new DatabasePoolManager();
// 🟢 WORKED: Retrieving the singleton instance
const db1 = DatabasePoolManager.getInstance(); // "[DatabasePool]: Opened pool with ID: conn_a1b2c3"
const db2 = DatabasePoolManager.getInstance(); // (No output! Returns existing instance)
db1.query("SELECT * FROM users");
// Both variables point to the exact same reference in memory!
console.log(db1 === db2); // true!
5. Reserved Static Names in JavaScript#
Because static members attach directly to the Class Constructor Function (which is an instance of JavaScript’s built-in Function object), certain property names are forbidden as static declarations:
name(Function name property)length(Function arity property)callerargumentsprototype
class CustomWidget {
// ❌ Compiler Error: Static property 'name' conflicts with built-in property 'Function.name'.
// public static name: string = "Widget";
// 🟢 GOOD: Use a non-reserved identifier name
public static widgetName: string = "Widget";
}Summary & Next Steps#
In this episode:
- We distinguished instance members (
new Class()) from static members (Class.member). - We combined static members with access modifiers (
private static,public static). - We executed complex startup logic using ES2022 Static Initialization Blocks (
static {}). - We implemented the Singleton Pattern using private constructors and static
getInstance()methods. - We identified reserved static names (
name,length,prototype).
In Episode 24: The Polymorphic this Type, we will explore fluent builder APIs and method chaining using TypeScript’s polymorphic this return type!

