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

inversify-typesafe

v0.5.13

Published

Boost InversifyJS with Type Safety.

Readme

import { createTypesafeContainer, returnTypesafeInject, TypesafeServiceConfig } from "inversify-typesafe";

// https://inversify.io/docs/introduction/dependency-inversion/
interface Weapon {
  damage: number;
}

class Katana implements Weapon {
  public readonly damage: number = 10;
}

export const typesafeInject = returnTypesafeInject<Services>()

class Ninja {
  constructor(
    @typesafeInject("weaponServiceId") // compile error if a parameter value is not a key of Services
    public readonly weapon: Weapon,
  ) { }
}

export type Services = {
  "ninjaServiceId": Ninja; // class
  "weaponServiceId": Weapon; // interface
};

export const serviceConfig: TypesafeServiceConfig<Services> = {
  // compile error if not compatible with Ninja
  "ninjaServiceId": (bind) => bind().to(Ninja),
  // compile error if not compatible with Katana. Use the second parameter if you need to access the container
  "weaponServiceId": (bind, _container) => bind().to(Katana),
};

const typesafeContainer = createTypesafeContainer(serviceConfig);

console.log(typesafeContainer.get("ninjaServiceId").weapon.damage);

TL;DR

inversify-typesafe adds compile-time type safety to InversifyJS without limiting its features. Define a Services map, register each service with TypesafeServiceConfig, and create a container with createTypesafeContainer. Service IDs are then autocompleted and their return types are inferred, while unknown IDs and incompatible bindings fail at compile time.

  • Define one Services map whose string keys are service IDs and whose values are the types returned for those IDs.
  • Declare a TypesafeServiceConfig<Services> containing every key in Services, and bind each key to a compatible implementation with the provided bind() function.
  • Pass the config to createTypesafeContainer; let TypeScript infer the container type instead of adding a generic argument manually.
  • Resolve services with container.get("serviceId"). Do not cast service IDs or result types, because doing so bypasses the library's compile-time checks.
  • For constructor injection, create a project-local decorator with returnTypesafeInject<Services>() and use it instead of InversifyJS's inject for mapped service IDs.
  • Use container._get(...) only when the original InversifyJS get API is required, such as for class or symbol identifiers. All other container methods retain their normal InversifyJS behavior.
  • Keep the Services map, service config, get calls, and injection decorators synchronized whenever a service is added, removed, or renamed.

Background

InversifyJS is a powerful and lightweight inversion of control container for JavaScript & Node.js apps powered by TypeScript. Although it is excellent on its own, adding a few more type declarations allows you to write more type-safe code by leveraging TypeScript's powerful type system. Wouldn't it be great if entering just a service ID automatically infers type of the service, and if entering an unregistered service ID could be magically detected at compile time? I wrote this library to create a type-safe container by exploiting TypeScript's String Literal Types and introduce a service registration method inspired by Spring.

Philosophy

In implementing the inversify-typesafe, I considered the following points:

  1. The library proposes an opinionated service registration method, but it should not limit InversifyJS's features.
  2. Users of the library should be able to use all features of InversifyJS whenever they want.
  3. While adhering to the above two principles, user mistakes should be caught at compile time as much as possible.
  4. The types that the library user needs to declare should be minimized.

Good Things

  • Entering a string service ID into the container automatically infers the registered type without additional type writing.
  • When entering a string into the get method to find a service, you can check registered service IDs via autocomplete in your code editor.
  • Compile-time errors occur if you enter a service ID that is not registered in the container.
  • Compile-time errors occur if you enter an unregistered service ID when injecting a service.
  • No additional peer dependencies. Just inversify and reflect-metadata.
  • 100% test coverage.

Installation

Via npm

npm install inversify-typesafe

Via yarn

yarn add inversify-typesafe

Via pnpm

pnpm add inversify-typesafe

Demo

Try it out on Stickblitz.

Types

https://inversify-typesafe.myeongjae.kim/modules.html

Usage

1. Declare Services Map Type

export type Services = {
  "ninjaServiceId": Ninja; // class
  "weaponServiceId": Weapon; // interface
};

Users should write Services(or whatever name you want) map type to declare the services that will be registered in the container. The keys of the Services type are used as service IDs. While InversifyJS registers various types (class, symbol, etc.) as service IDs, inversify-typesafe uses only string types as service IDs. Using string allows exploiting TypeScript's String Literal Types feature to provide magical type safety.

2. Write Service Config

import { TypesafeServiceConfig } from "inversify-typesafe";

export const serviceConfig: TypesafeServiceConfig<Services> = {
  "ninjaServiceId": (bind) => bind().to(Ninja),
  "weaponServiceId": (bind, _container) => bind().to(Katana),
};

This library provides a utility type called TypesafeServiceConfig<T>. TypesafeServiceConfig<T> constrains the keys of type T to be used as service IDs. Passing the previously declared Services type as the type parameter to TypesafeServiceConfig restricts usage to only the keys of the Services type. If you enter a key that does not exist in Services or do not provide a function for every key in Services, a compile-time error occurs, allowing users to write code more safely.

The object's values use lambdas to allow users to utilize all binding features of Inversify. The lambda accepts bind as the first parameter and container as the second. The first parameter is a thunk () => container.bind(serviceId) to bind the service ID to the container. Since the thunk to bind the object's key as a service ID is passed as a parameter, the user can choose how to map a service to the service ID. If the user attempts to map a service that is incompatible with the Services type declaration, a compile-time error occurs.

The lambda's second parameter receives container. For simple cases, using only the first parameter bind is sufficient, but you can utilize the second parameter if you need to access the container directly during the service registration process.

3. Create Typesafe Container

import { createTypesafeContainer } from "inversify-typesafe";

const typesafeContainer = createTypesafeContainer(serviceConfig);

The createTypesafeContainer() function takes an argument of type TypesafeServiceConfig<T> and returns TypesafeContainer<T>. Users do not need to specify generic type parameters manually.

4. Get Service

const ninjaService = typesafeContainer.get("ninjaServiceId");

Passing a key of the user-declared Services type as an argument returns the bound service. The return type is inferred well without any additional type writing, and registered service IDs can be checked via autocomplete in the code editor.

Entering a value that is not a key of Services causes a compile error.

5. Inject Service

import { returnTypesafeInject } from "inversify-typesafe";

export const typesafeInject = returnTypesafeInject<Services>()

class Ninja {
  constructor(
    @typesafeInject("weaponServiceId")
    public readonly weapon: Weapon,
  ) { }
}

Calling the high order function returnTypesafeInject<T>() with the user-declared Services type as the type parameter returns a decorator function. Entering a value other than a key of the Services type into this decorator's parameter causes a compile error.

6. Every InversifyJS feature is possible

import { ServiceIdentifier } from "inversify";

const ninjaService = typesafeContainer._get("ninjaServiceId" as ServiceIdentifier<Ninja>);

The _get method of type TypesafeContainer<T> performs the same function as the get method of the existing Container type. You can use the _get method when you need the original get method rather than the type-safety enhanced function.

All methods except the get method are identical to the InversifyJS Container type.

inversify-typesafe-spring-like

Add-On Library for inversify-typesafe to make it more like Spring.

https://github.com/myeongjae-kim/inversify-typesafe/tree/main/packages/inversify-typesafe-spring-like

Try it out on Stickblitz.

Contributing

Code Quality Process

When making changes to the codebase, follow this verification process before committing:

# 1. Run linting
pnpm lint

# 2. Build the project
pnpm build

# 3. Run tests (ensure 100% coverage is maintained)
pnpm test

# 4. If all checks pass, commit your changes
git add .
git commit -m "type(scope): description"

| Step | Command | Purpose | |------|---------|---------| | 1 | pnpm lint | Code style and static analysis | | 2 | pnpm build | TypeScript compilation | | 3 | pnpm test | Unit tests with 100% coverage | | 4 | git commit | Commit verified code |

Commit Message Convention:

Follow the Conventional Commits format:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • refactor: Code refactoring
  • test: Test changes
  • chore: Build/config changes

License

MIT © Myeongjae Kim