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 🙏

© 2025 – Pkg Stats / Ryan Hefner

stimshot

v0.1.1

Published

A dead-simple, modern, and lightweight (~4kb) Dependency Injection library for TypeScript

Readme

stimshot

CI minified size minified gzipped size tree shaking support

A dead-simple, modern, and lightweight (~2kb) Dependency Injection library for TypeScript.

Why another DI framework?

Stimshot was inspired from InversifyJS, Tsyringe, InjectionJS (outside the context of Angular). These libraries have some fundamental issues when used with modern TypeScript.

Many existing DI libraries for TypeScript rely on the older experimental decorators and reflection libraries like reflect-metadata. This approach forces you to enable emitDecoratorMetadata in your tsconfig.json, which depends on TypeScript's type-information—information that is erased at compile time.

Often this leads to runtime errors, especially when using the new import type syntax. Most DI libraries were not designed with this in mind, and as a result, they fail to resolve dependencies correctly and lead to runtime issues.

Stimshot was built with a different philosophy:

  • Explicit & Guess-less: No magic strings, no fragile type-reflection. You explicitly ask for what you need. What you see is what you get.
  • Weightless: The entire library is one small file with no dependencies.
  • Modern: Built for modern TypeScript (5.0+) using standard Stage 3 Decorators.
  • Simple APIs: The API surface is tiny, intuitive, and easy to understand.

This library does not use or require reflect-metadata or experimentalDecorators or emitDecoratorMetadata like other DI libraries.

Comparison with Other Libraries

| Feature | stimshot | InversifyJS | Tsyringe | InjectionJS | |-----------------------------|:--------:|:-----------:|:--------:|:-----------: | reflect-metadata | ✅ Not needed | Yes minified size | Yes minified size | Yes minified size | | Library size | ✅ minified size | minified size | minified size | minified size | | Modern TypeScript Support | ✅ Yes | No | Partial | No | | Extensive feature set | Only core features | ✅ | ✅ | ✅ |

Why Use Dependency Injection?

Using a DI pattern is a cornerstone of modern software design. It helps you build:

  • Modular Code: Classes don't create their own dependencies; they just receive them. This makes your code loosely coupled and easier to manage.
  • Testable Code: DI makes testing a breeze. You can easily "replace" a real database or HTTP service with a fake (mock) version during tests.
  • Clean Architecture: It helps enforce the Single Responsibility Principle, leading to a codebase that's easier to scale and maintain.

Features

  • Modern TypeScript: Uses standard Stage 3 decorators (available in TS 5.0+).
  • No reflect-metadata: No hacks or reliance on fragile type information.
  • No experimentalDecorators: Uses modern typescript's stage 3 decorators.
  • 🧠 Simple API: A minimal set of 5 functions: @shared, @fresh, resolve, replace, and reset.
  • 🧪 Testable by Design: replace and reset make unit testing trivial and safe.

Installation

npm install stimshot

Basic Usage

The design is simple:

  1. Decorate your classes with @shared() (for singletons (shared instances)) or @fresh() (for new instances).
  2. Resolve your dependencies using resolve().
import { resolve, shared } from 'stimshot';

@shared() // Means singleton
class Chip {
  public readonly name = "tensor";
}

@shared()
class Screen {
  public readonly dpi = 441;
}

@shared()
class Phone {
  private readonly chip = resolve(Chip); // Define dependency like this

  constructor(
    public readonly screen = resolve(Screen) // Or like this
  ){}

  getSpecs() {
    return `Phone with ${this.chip.name} chip and ${this.screen.dpi} DPI screen.`;
  }
}

// --- Then to make Phone instance ---
const phone = resolve(Phone); // Don't use 'new Phone()' method!
phone.getSpecs();

Testing with Mocks

stimshot makes it trivial to replace dependencies in your tests.

import { resolve, shared, replace, reset } from 'stimshot';

@shared()
class Chip {
  public readonly name = "tensor";
}

@shared()
class Phone {
  private readonly chip = resolve(Chip); // Define dependency like this

  getSpecs() {
    return `Phone with ${this.chip.name} chip`;
  }
}
// --- In your test setup ---
// I want to test the Phone class logic without using the real Chip class.
// This is a good practice in unit testing to isolate the class under test.
// So now Chip class will not interfere with our Phone tests.

// Create a mock implementation for Chip
@shared()
class MockChip {
  public readonly name = "mock-tensor";
}

replace(Chip, { useClass: MockChip }); // Replace Chip with MockChip

const phone = resolve(Phone); // Resolve Phone, which now uses MockChip
console.log(phone.getSpecs()); // Outputs: Phone with mock-tensor chip

You can also replace with a simple object (useValue) or a function (useFactory).

API Reference

Decorators

  • @shared(): Class decorator. Registers the class as a "singleton." A single instance will be created on the first resolve and shared for all subsequent calls (This is what you usually want).
  • @fresh(): Class decorator. A new instance will be created every time it is resolved.

Functions

  • resolve(Token): Resolves a dependency from the container. Token is the class constructor (e.g., resolve(Database)).
  • replace(Token, options): Used for testing. Replaces the registered Token with a mock implementation.
    • options.useClass: Replaces with another registered class.
    • options.useValue: Replaces with a specific value (e.g., a mock object).
    • options.useFactory: Replaces with a function that returns the instance.
  • reset(): Used for testing. Resets the entire container, clearing all shared instances and removing all replacements, restoring the original configuration.

License

MIT © 2025 Vajahath Ahmed