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 🙏

© 2024 – Pkg Stats / Ryan Hefner

mini-di-container

v0.1.6

Published

A minimum, type-safe and straightforward dependency injection container for TypeScript

Downloads

14

Readme

npm version CI License: MIT

mini-di-container

A minimum, type-safe and straightforward dependency injection container for TypeScript.

npm install mini-di-container

Philosophy

  • Typesafe: This package provides fully typed interfaces. If there are no compilation errors, then your code runs as you expected.
  • No annotation: This package is NOT annotation-based DI library.
  • Simple: Few public interfaces and parameters. When you read the small example code below, you will know everything about this library.
  • Plain: Few implicit rules and no proprietary syntax. If you can read TypeScript, then you can use this library intuitively.

Key features

  • Instance management: Dependency instances are instanciated and cached per container.
  • Lazy evaluation: Processes are lazy as much as possible. Each dependency instances are not instantiated until it is actually used.
  • Scope management: You can easily achieve singleton scoped, request scoped or any scoped contaniner you want. You can also use external parameters (e.g. request object) to build your dependencies.

Usage

import { type Infer, scope } from 'mini-di-container';

// Your types, classes and interfaces to be managed with DI container
interface Logger {
  log(message: string): void;
}
type GreetingConfig = {
  greetingWord: 'Hello' | 'Hi';
};
class GreetingService {
  constructor(readonly config: GreetingConfig) {}
  greet(name: string): string {
    return `${this.config.greetingWord}, ${name}.`;
  }
}
class TalkingService {
  constructor(
    readonly greetingService: GreetingService,
    readonly fromName: string
  ) {}
  talkTo(toName: string): string {
    return `${this.fromName} said: ${this.greetingService.greet(toName)}`;
  }
}

// Defines a new container scope, here example is a singleton-scoped.
const singletonScope = scope()
  .provide({
    // builder methods of dependencies.
    logger: (): Logger => ({
      log: console.log,
    }),
    config: (): GreetingConfig => ({ greetingWord: 'Hello' }),
  })
  .provide({
    // You can use already defined dependencies to build another dependencies.
    greetingService: ({ config }): GreetingService =>
      new GreetingService(config),
  });
// Instanciate singleton-scoped container.
const singletonContainer = singletonScope.instanciate({});

// Define another scope. You can specify scope-specific parameter. As an example,
// here is `{ request: Request }`.
const requestScope = scope<{ request: Request }>()
  .static(singletonContainer)
  .provide({
    // Define request-scoped dependencies.
    talkingService: ({ greetingService }, { request }) =>
      new TalkingService(
        greetingService,
        request.headers.get('x-greeter-name') ?? 'anonymous'
      ),
  });

// The request-scoped container is not instanciated yet, since it is instanciated
// per a request.

// Your request handler as an example.
// Here assuming the request header contains `X-Greeter-Name: Alice`.
function requestHandler(request: Request) {
  // Instanciate the request-scoped container per request, with the scope-specific
  // external parameters.
  const requestScopedContainer = requestScope.instanciate({
    request,
  });

  // Of course, you can use each dependency instances directly.
  const { logger, config, talkingService } = requestScopedContainer;
  logger.log(config.greetingWord); // => 'Hello'
  logger.log(talkingService.talkTo('Bob')); // => 'Alice said: Hello, Bob.'

  // Another usage is passing the container itself to a downstream method.
  // This pattern is useful e.g. when the middreware method can't know which
  // dependencies will be used in the downstream.
  logger.log(doGreeting('Carol', requestScopedContainer));
  // => 'Alice said: Hello, Carol.'
}

type Dependencies = Infer<typeof requestScope>;
function doGreeting(
  toName: string,
  { logger, greetingService }: Dependencies
): string {
  logger.log('doGreeting is called');
  return greetingService.greet(toName);
}

License

MIT