Random Thoughts | Singleton Class in TypeScript

January 18th, 2024

Random Thoughts - Singletons in TypeScript

At work recently, I decided to implement a class as a singleton as the class needed to be of a single instance across the codebase. This summary will discuss a singleton class in TypeScript, and will also discuss a tip for hiding the getInstance call to consumers of the class in the classic implementation.

Creating a Singleton Class in TypeScript

Implementing a singleton class in TypeScript involves ensuring that a class has only one instance and provides a global point of access to it. This design pattern proves valuable when a single instance of a class is needed to coordinate actions across the system. In TypeScript, achieving a singleton involves a combination of a private constructor, a private static instance variable, and a static method for retrieving or creating the singleton instance.

class SingletonClass {
  private static instance: SingletonClass | null = null;

  private constructor() {
    // Private constructor to prevent external instantiation
  }

  public static getInstance(): SingletonClass {
    if (!SingletonClass.instance) {
      SingletonClass.instance = new SingletonClass();
    }
    return SingletonClass.instance;
  }

  public doSomething(): void {
    console.log("Singleton instance is doing something.");
  }
}

// Example of using the singleton class
const singletonInstance1 = SingletonClass.getInstance();
const singletonInstance2 = SingletonClass.getInstance();

console.log(singletonInstance1 === singletonInstance2); // Output: true
singletonInstance1.doSomething();

Singleton Class Implementation

In the provided TypeScript code, the SingletonClass is structured with a private static instance variable to hold the singleton instance, a private constructor to restrict external instantiation, and a static getInstance method responsible for creating or retrieving the singleton instance. Clients can obtain the singleton instance using getInstance() and subsequently perform operations on that single instance. The use of a singleton pattern ensures that there is only one instance of the class throughout the application, promoting consistency and centralized control.

Improving the Singleton Class in TypeScript

In TypeScript, refining the implementation of a singleton class involves making the getInstance method a static method directly accessible on the class itself. This enhancement eliminates the need for consumers of the class to explicitly call getInstance, simplifying the usage of the singleton pattern.

class SingletonClass {
  private static instance: SingletonClass | null = null;

  private constructor() {
    // Private constructor to prevent external instantiation
  }

  public static doSomething(): void {
    const instance = SingletonClass.getInstance();
    console.log("Singleton instance is doing something.");
  }

  private static getInstance(): SingletonClass {
    if (!SingletonClass.instance) {
      SingletonClass.instance = new SingletonClass();
    }
    return SingletonClass.instance;
  }
}

// Example of using the singleton class
SingletonClass.doSomething();

Singleton Class with Direct Access

In this refined version, the SingletonClass now features a static method doSomething, directly invoking the singleton instance creation without requiring consumers to explicitly call getInstance. This modification streamlines the usage of the singleton pattern, providing a more straightforward and convenient interface for clients. The private static getInstance method remains responsible for creating or retrieving the singleton instance, maintaining the desired characteristics of the singleton design pattern, however, clients do not need to know of this method, abstracting their understanding that the class is a singleton, and allowing them to interact with the class in a more streamlined manner.