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

ascend-ioc

v1.0.3

Published

Inversion of control system for building TypeScript node applications.

Downloads

16

Readme

Ascend

A simple and easy to use lightweight inversion of control (IoC) container made specifically with TypeScript in mind.

What makes Ascend unique is that it is tailor-made for a pure singleton setup.

That means that when you resolve a service via an Ascend resolve, you will always get the same instance for that specific resolver.

Why?

A big pitfall of many IoC systems is the fact that transient and singleton state can easily be mixed up without too much thought. By not managing transient state, Ascend ensures that the implementor has to maintain its transient state.

Unlike many other implementations for JS/TS, there's no need to maintain a set of "keys" for the services that you register with Ascend. Registration and resolving is performed simply via the types themselves.

Install

NPM

npm install ascend-ioc reflect-metadata

reflect-metadata

  • If your project is a library, add reflect-metadata to types in your tsconfig.json.
  • If your project is an app, add import "reflect-metadata"; to your index.ts-equivalent.

Concepts

Below description of the various concepts implemented by Ascend.

Resolver

The resolver is the main entry point of Ascend. Once you have invoked the ascend bootstrap function, you receive a resolver. From here, you can begin resolving services for your application:

import { ascend } from "ascend-ioc";

const resolver = ascend({
  // Specify IOptions parameters here...
});

resolver.resolve(ExampleService).doSomething();

For documentation of IOptions, see src/IOptions.ts.

Service

Services are the core concept of Ascend. You register services with their respective implementations with Ascend prior to creating the resolver. Once you receive a resolver, you can use it to get dependency-injected instances of the registered services.

A service implementation should be decorated with the @Implements(...) decorator:

export class ExampleService {
  // ...
}

@Implements(ExampleService)
export class ExampleServiceImpl implements ExampleService {
  // ...
}

If you have a self-implementing service, you can use the @Service decorator which is syntactic sugar for the following scenario:

@Implements(ExampleService)
export class ExampleService {
  // ...
}

Bootstrapper

A bootstrapper is used by Ascend to provide access to the registrator prior to creating the resolver. This allows an implementor to register services or instances manually without having to go through the decorator system.

This is useful for cases where you might want to inject an instance from another library or application into your application.

A bootstrapper must always implement the IBootstrapper interface. If you want the bootstrapper to be automatically discovered by Ascend, you should also decorate it with the @Bootstrapper decorator.

@Bootstrapper
export class ExampleBootstrapper implements IBootstrapper {
  public bootstrap(registrator: Registrator): void {
    // ...
  }
}

For documentation on Registrator, see src/Registrator.ts.

Examples

Implementation

See the following files for the main entry points of a working implementation.

From there, you can look at any additionally imported files for more information.

Note: The imports are project-local here, in your project you'd use import ... from "ascend-ioc" instead of import ... from "../../src.

@all

The @all decorator allows you to specify that a constructor parameter should receive all implementations of the dependency.

export class Dependency {
  // ...
}

@Implements(Dependency)
export class DependencyImpl1 {
  // ...
}

@Implements(Dependency)
export class DependencyImpl2 {
  // ...
}

@Implements(Example)
export class Example {
  private readonly dependencies: Dependency[];

  public constructor(@all(Dependency) dependencies: []) {
    this.dependencies = dependencies;
  }

  // ...
}

Gotchas

Service identification via interfaces

Due to various restrictions of the current state of TypeScript, you cannot use interfaces to identify or register services since they are not emitted when compiled.

Instead, you will have to create a class and use that in place of the interface:

export class ExampleService {
  public doSomething(): void {
    throw new Error("Not implemented");
  }
}

Automatic service discovery

Since files are only included when they are required, you will have to re-export all service implementation types so that they are available in the application and Ascend can discover them.

This is usually made through an ascender.ts imported in your index.ts-equivalent:

export * from "./something/all";
export * from "./other/all";

export { ascend } from "ascend-ioc";

A tip here is to use barrel files to reduce the maintenance of your ascender file.