How to utilize DI pattern in your application

Dependency-Injection-TS

Service
Service
@Injectable()
class App

Dependency Injection Pattern in TypeScript

Kacper Walczak · 05-11-2023

  • Learn how to implement Dependency Injection in TS.

Dependency Injection Pattern in TypeScript.

Note! Unfortunately it does not work with Bun, but it works with NodeJS.

Usage

Pattern usage:

 
// Simple class for dependency injection testing
class Test {
  constructor() {
    console.log("Test constructor - created");
  }
 
  doSomething(): void {
    console.log("Test did something");
  }
}
 
// Entry point class
@Injectable()
class App implements OnDestroy {
  constructor(public test: Test) {}
 
  onDestroy(): void {
    console.log("App destroyed");
  }
}
 
const [entryClass, destroy] = bootstrap<App>(App);
// Initialize the entry point class instance
// Output:
//   Injector resolving class Test
//   Test constructor - created
//   Injector created class Test
//   Injector resolving class App
//   Injector created class App
 
entryClass.test.doSomething();
// Use the entry point class instance
// Output:
//   Test did something
 
destroy();
// Destroy the entry point class instance
// Output:
//   App destroyed

Pattern

Import reflect-metadata

Import the reflect-metadata package to be able to use Reflect's metadata.

import "reflect-metadata";

Type interface

Create type for classes that will be resolved in Injector.

export interface Type<T> {
  new (...args: any[]): T;
}

Injectable decorator

Decorator function to annotate classes which can inject another ones in constructors.

@Injectable()
class App { /* ... */ }
export const Injectable = (): ((target: Type<any>) => void) => {
  return (target: Type<any>) => {};
};

OnDestroy interface

Lifecycle hook that is used for releasing a resource.

It will be called automatically by DI container.

export interface OnDestroy {
  onDestroy(): void;
}

Injector class

Injector class that is used for resolving classes.

class App { /* ... */ }
const injector = new Injector();
 
// bootstrap all dependencies
const entryClass = injector.resolve<App>(App);
/**
 * Every entry point class instance starts its own dependency container.
 * Injector ensures that all decorated classes in the container are singletons.
 */
export class Injector extends Map {
  public resolve<T>(target: Type<any>): T {
    const tokens = Reflect.getMetadata("design:paramtypes", target) || [];
    const injections = tokens.map((token: Type<any>) => {
      return this.resolve<any>(token);
    });
    console.log(`Injector is resolving class ${target.name}`);
 
    const classInstance = this.get(target);
    if (classInstance) {
      return classInstance;
    }
 
    const newClassInstance = new target(...injections);
    this.set(target, newClassInstance);
 
    console.log(
      `Injector has created class ${newClassInstance.constructor.name}`
    );
 
    return newClassInstance;
  }
 
  public onDestroy(): void {
    for (const value of this.values()) {
      if (typeof value["onDestroy"] === "function") {
        value["onDestroy"]();
      }
    }
 
    this.clear();
  }
}

Bootstrap function

Function that is used for bootstrapping the entry point class instance.

const [entryClass, destroy] = bootstrap<App>(App);
/**
 * Bootstraps the entry point class instance of type T.
 *
 * @returns entry point class instance and the "destroy" function which destroy the DI container
 */
export const bootstrap = <T>(target: Type<any>): [T, () => void] => {
  // there is exactly one Injector pro entry point class instance
  const injector = new Injector();
  // bootstrap all dependencies
  const entryClass = injector.resolve<T>(target);
 
  return [entryClass, () => injector.onDestroy()];
};

That's it! Now you can use this pattern in your applications/libraries.

READ

Latest readings

  • Readings are sites which will help you with detailed

  • information about given topic. Read latest ones from Learn.

AI

06-03-2026

Local Voice Assistant with Ollama
  • Build your own local voice assistant powered by Ollama.

AI

06-03-2026

AI YouTube Thumbnail Generator
  • Generate YouTube thumbnails with FastAPI and Ollama.

Architecture

05-09-2024

Graph DB usage comparison
  • Compare Neo4j and Tigergraph databases, which is easier to work with, etc.