Explain Codes LogoExplain Codes Logo

Typescript static classes

javascript
static-members
abstract-classes
singleton-pattern
Anton ShumikhinbyAnton Shumikhin·Mar 8, 2025
TLDR

To replicate a static class in TypeScript, define a class encompassing exclusively static members. This class can't be instantiated; instead, use its members by calling them through the class name.

class Utils { static constant: number = 42; static compute(): number { return Utils.constant * 2; } } // How to use it console.log(Utils.constant); // Output: 42 console.log(Utils.compute()); // Output: 84

Here, each member is prefixed with static, making them accessible sans an instance.

Introduction to Static Members

Static in TypeScript qualifies methods and properties as belonging to the class rather than an instance of it, resembling C# and other languages. Therefore, classes with just static members aren't instantiated via new.

Abstract Classes in TypeScript

TypeScript introduces the concept of abstract classes which, like blueprints, contain static properties and methods but cannot be instantiated directly.

abstract class Singleton { static instance: Singleton; private constructor() { // This class is too cool to be instantiated 😉 } static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton(); // Constructor logic here } return Singleton.instance; } }

This pattern not only bars instantiation but allows lazy initialization of the instance, echoing a singleton pattern behavior, akin to static class usage.

Immutable Static Properties

To declare a constant that remains unaltered, employ the readonly keyword.

class Configuration { static readonly VERSION: string = '1.0.0'; } console.log(Configuration.VERSION); // Output: '1.0.0'

Concealed Static Data

For concealment of internal class logic, private static variables may be utilized. Ideal for class-bound constants or shared states.

class InternalCounter { private static count: number = 0; static increment(): number { return ++InternalCounter.count; // Shh.. don't tell anyone 🤫 } }

Defying Instantiation

An absolutely unreal private constructor deters any class instantiation, even by subclasses.

class NonInstantiable { private constructor() { throw new Error("I refuse to be instantiated!"); // Talk about having a will! } } // new NonInstantiable(); // This line throws an error by intention.

TypeScript Modules 101

Structuring Your Code

Group related functions and properties with TypeScript modules, similar to static classes, but leaning towards a more functional programming approach.

// MathUtils.ts export function square(number: number): number { return number * number; } // Another file import { square } from './MathUtils'; console.log(square(5)); // Output: 25

Magic of Encapsulation

TypeScript compiles to JavaScript, meaning the modules can conceal their variables, preventing global scope pollution. It's like making your codebase clean as a whistle!

Private... But Not Quite So

Expose functions utilizing module-level variables while keeping the state protected, similar to private static members in a class.

// Counter.ts let count = 0; export function incrementCount() { return ++count; // "Counting is hard!" - said no computer, ever. }

Ready, Steady, Implement Static Constructors!

Static Initialisation Logic

TypeScript doesn't inherently support static constructors, but you can simulate this with an Immediately Invoked Function Expression (IIFE):

class Database { static readonly connection; static { Database.connection = (function () { // Connection logic here return new Connection(); // "New connection, who this?" 😎 })(); } }

Utility Functions & Patterns Galore

Outside of classes, utilize functions favoring flexibility and organization sans class syntax constraints.

Consistent TypeScript-ing

Always refer to authoritative sources like the TypeScript Language Specification for the most accurate and up-to-date advice on using static and abstract features in TypeScript.