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

@kanian77/tject

v1.2.2

Published

A dependency injection library for TypeScript.

Readme

tject — Dependency Injection for TypeScript

A lightweight TypeScript dependency-injection system with support for:

  • singleton and transient lifecycles
  • token-based providers (string / symbol / class)
  • value and factory providers
  • a module system and bootstrap helper

Core APIs

  • Service decorator: src/decorators/Service.ts
  • Field decorator: Injectsrc/decorators/Inject.ts
  • Programmatic injection: injectsrc/functions/inject.ts
  • Register values: registerValuesrc/functions/registerValue.ts
  • Module bootstrap: bootstrapsrc/functions/bootstrap.ts
  • Reset container (tests): resetContainersrc/functions/resetContainer.ts

Quick install

bun add @kanian77/tject

or

npm install @kanian77/tject

Basic usage

Register a class as a service with the decorator:

@Service()
class MyService {
  getValue() {
    return 'hello';
  }
}

Inject a dependency into a field:

const LOGGER = Symbol('Logger');

@Service({ token: LOGGER })
class Logger {
  log(msg: string) {
    console.log(msg);
  }
}

@Service()
class Consumer {
  @Inject({ token: LOGGER }) private logger!: Logger;
  doWork() {
    this.logger.log('work');
  }
}

Programmatic injection:

const svc = inject<MyService>(MyService);
// See src/functions/inject.spec.ts for more info

See inject.ts and inject.spec.ts for more info Register values or factories (via Module providers):

// value provider
{ provide: 'CONFIG', useValue: { apiUrl: 'https://api' } }

// factory provider
{ provide: 'ID', useFactory: () => crypto.randomUUID() }

// class provider (raw class)
{ provide: 'MyServiceToken', useClass: MyService }

Modules and bootstrap

const appModule = new Module({
  providers: [
    { provide: 'CONFIG', useValue: { env: 'dev' } },
    { provide: 'MyServiceToken', useClass: MyService },
  ],
});
bootstrap(appModule);

Module providers — the three supported forms

When configuring a Module, a provider can be declared in one of three ways. The module system supports:

  • useClass — register a class to be instantiated when the token is requested

    { provide: 'MyToken', useClass: MyService }
  • useValue — register a static value (useful for configuration)

    { provide: 'CONFIG', useValue: { apiUrl: 'https://api' } }
  • useFactory — register a factory function that returns the value/instance

    { provide: 'ID', useFactory: () => Math.random().toString(36).slice(2) }

Modules and imports

Modules may import other modules. Importing a module makes its providers available to the importing module (the bootstrap process walks imports and registers providers from imports as well as the root module). Example:

const moduleA = new Module({
  providers: [{ provide: 'A', useClass: ServiceA }],
});
const rootModule = new Module({
  imports: [{ module: ModuleA }],
  providers: [{ provide: 'B', useClass: ServiceB }],
});
bootstrap(rootModule);

Modules are the preferred way to compose large applications and to group related providers and configuration.

Import bindings (provider mapping)

In addition to importing modules, you can declare binds on an import to map providers between the importing module and the imported module. The ImportOptions shape looks like this:

interface ImportOptions {
  module: Module;
  binds?: { to: Token; from: Token }[];
}

binds declares explicit provider mappings that tell the bootstrap how to satisfy service dependencies automatically. When a bind is present, bootstrap() will add the imported provider token to the importing service's dependency list so you typically don't need to add an explicit @Inject for that dependency. This makes modules more descriptive and enforcing: a module can declare how imported providers fulfill its local service dependencies. You can still use @Inject if you prefer to see injections close to the code using them.

Example (from tests):

// moduleX provides ServiceX under token 'ServiceX'
const moduleX = new Module({
  providers: [{ provide: 'ServiceX', useClass: ServiceX }],
});

// moduleY provides ServiceY which depends on ServiceX but is declared under a different token
const moduleY = new Module({
  providers: [{ provide: 'ServiceY', useClass: ServiceY }],
  imports: [
    {
      module: moduleX,
      binds: [{ to: 'ServiceY', from: 'ServiceX' }],
    },
  ],
});

// When bootstrapping the root module, the bind is processed and
// ServiceY receives ServiceX as a dependency automatically.
bootstrap(new Module({ imports: [{ module: moduleY }] }));

const instanceY = inject('ServiceY');
// instanceY.getValue() can now call into ServiceX because the dependency was added

// Look at tests for more examples of import binds with scopes: src/functions/bootstrap.spec.ts

Runtimes and decorator support

The new TypeScript decorator standard (Stage 3) is supported differently by runtimes. Choose the workflow that matches your runtime.

  1. Deno — Native Stage 3 support
  • Deno executes TypeScript natively and supports Stage 3 decorators.
  • How to run:
deno run --allow-read your-file.ts
  • tsconfig: Deno is zero-config; omit the old experimental decorator flag (do not set "experimentalDecorators": true).
  1. Node.js — Transpile first
  • Node's V8 does not yet support Stage 3 decorator syntax. Transpile first with tsc, then run the compiled JavaScript.
  • How to run:
# 1) compile
npm run build

# 2) run compiled JS
node dist/your-file.js
  • tsconfig: Use Stage 3 settings — omit or set "experimentalDecorators": false so tsc emits Stage 3-compatible transpiled JS.
  1. Bun — Two modes (legacy native vs transpiled JS)
  • Bun's native TypeScript transpiler supports legacy decorators only (the older emit).
  • To use Stage 3 decorators (this project): transpile with tsc and run the compiled JS with Bun or Node.
npm run build
bun run dist/your-file.js
  • Summary:
    • Bun native (bun run file.ts): legacy decorators only (requires "experimentalDecorators": true in tsconfig).
    • Bun running compiled JS: works with Stage 3 (transpile with tsc which uses "experimentalDecorators": false).

Recommended tsconfig for Stage 3 (this repository)

  • See tsconfig.json. Important bits:
    • "experimentalDecorators": false (or omit) to use the new Stage 3 decorators.
    • Compile to a target like ES2015 so tsc emits plain JS that Node/Bun can run.

Running tests (notes)

  • Tests in this repo are TypeScript test files. Bun's native test runner for .ts files will use Bun's transpiler and therefore may fail when Stage 3 decorators are present.
  • Recommended approaches:
    1. Transpile first with tsc then run compiled tests (or test harness) against dist/.
    2. Use Deno for native Stage 3 support if you want to run TypeScript directly.

Helpful files

  • Main exports: src/index.ts
  • Decorators: src/decorators/Service.ts, src/decorators/Inject.ts
  • Injector: src/functions/inject.ts
  • Bootstrap: src/functions/bootstrap.ts
  • Registry / reset: src/functions/serviceRegistry.ts, src/functions/resetContainer.ts
  • Config: package.json, tsconfig.json

Advanced Examples

For more complex usage scenarios, check out the following test files which serve as comprehensive examples:

Contributing

  • Open a PR. Run npm run build and verify behavior on your target runtime.

License

  • MIT