npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ts-singletonify

v2.0.3

Published

A Typescript utility to enforce singleton instances

Readme

🚀 ts-singletonify

GitHub License TypeScript Tests

A TypeScript utility to enforce singleton instances in your applications.

✨ Features

  • ✅ Simple API for creating singleton classes
  • 🔒 Strict TypeScript enforcement
  • 🔄 Works seamlessly with ES2020 and CommonJS modules
  • 🧪 Fully tested with Vitest

📦 Installation

To install using npm:

npm install ts-singletonify

Or using Yarn:

yarn add ts-singletonify

🚀 Usage

All you need is to pass your class to the Singleton function and it will singletonify your class. Any class should work, giving you full control over it.

import { Singleton } from "ts-singletonify";

class ExampleService {
  sayHello(): string {
    return "hello";
  }
}

const singleton = Singleton(ExampleService);
const instance1 = singleton.getInstance();
const instance2 = singleton.getInstance();

console.log(instance1 === instance2); // true
console.log(instance1.sayHello()); // "hello"

You can also specify the initialize function within your class and Singleton will pick it up and make sure it is run after instance is created:

class ExampleService {
  initialized = false;
  // This has to be named initialize
  initialize(): void {
    // some logic to perform the initialization 
    this.initialized = true;
  }
}
const singleton = Singleton(ExampleService);
const instance1 = singleton.getInstance();
const instance2 = singleton.getInstance();
expect(instance1).toBe(instance2);
expect(instance1.initialized).toBe(true);

Use AsyncSingleton for async initialization functions:

import { AsyncSingleton } from "ts-singletonify";

class ExampleService{
  initialize = false;
  async initialize(): Promise<void> {
    await new Promise((res) => setTimeout(res, 100));
    this.initialize = true
  }
}

// AsyncSingleton is a Promise that will attempt to run initialize().
const singleton = await AsyncSingleton(ExampleService)
const instance1 = singleton.getInstance();
const instance2 = singleton.getInstance();
console.log(instance1 === instance2);

initialize function can have any signature and accepts any parameters. You will need to pass these parameters into Singleton or AsyncSingleton function.

class ExampleService {
  initialized = false;

  async initialize(arg1: number, arg2: number): Promise<void> {
    await new Promise((res) => setTimeout(res, 100));
    this.initialized = true;
  }
}

//typescript will enforce the initialize signature with arg1: number and arg2: number to be passed to AsyncSingleton
const singleton = await AsyncSingleton(ExampleService, 2, 3);
const instance1 = singleton.getInstance();  
const instance2 = singleton.getInstance(); 

You can spread them as well ...[2,3]

class ExampleService {
  initialized = false;

  async initialize(arg1: number, arg2: number): Promise<void> {
    await new Promise((res) => setTimeout(res, 100));
    this.initialized = true;
  }
}

const singleton = await AsyncSingleton(ExampleService, ...[2, 3]);
const instance1 = singleton.getInstance();  
const instance2 = singleton.getInstance();
console.log(instance1 === instance2) // true
console.log(instance1.initialized) // true

or just pass an object for readability

class ExampleService {
  initialized: boolean = false;
  params: { arg1: string; arg2: number[] };

  constructor() {
    this.initialized = true;
  }

  initialize(params: { arg1: string; arg2: number[] }) {
    this.params = {
      arg1: params.arg1,
      arg2: params.arg2,
    };
  }
}
const params = {
  arg1: "test",
  arg2: [123, 12],
};

// Singleton enforces params to be { arg1: string, arg2: number[] }
const singleton = Singleton(ExampleService, params);
const instance1 = singleton.getInstance();
const instance2 = singleton.getInstance();

NOTE If you currently have a constructor that takes some arguments you will need to move this logic into the initialize function instead. If your constructor doesn't take any params it is alright to have some logic going on.

⚙️ Build

To compile the TypeScript code:

npm run build

🧪 Testing

Run unit tests using Vitest:

npm test

Run tests in watch mode:

npm run test:watch

Check coverage:

npm run coverage