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

@inversifyjs/strongly-typed

v1.2.2

Published

InversifyJs strong type definitions

Downloads

614

Readme

Test coverage npm version

@inversifyjs/strongly-typed

Type definitions for adding strong typing to the Container and @inject() decorator.

Getting started

This library can be used in a couple of ways, depending on your preference.

All usages wind up with you having a strongly-typed TypedContainer, which is a generic class that accepts a binding map as a type argument, which forms the contract that your container will adhere to:

import { TypedContainer } from '@inversifyjs/strongly-typed';

interface Foo { foo: string }
interface Bar { bar: string }

interface BindingMap {
  foo: Foo;
  bar: Bar;
}

const container = new TypedContainer<BindingMap>();

// Bindings are now strongly typed:

container.bind('foo').toConstantValue({foo: 'abc'}); // ok
container.rebind('foo').toConstantValue({unknown: 'uh-oh'}) // compilation error

let foo: Foo = container.get('foo') // ok
foo = container.get('bar') // compilation error
foo = container.get('unknown-identifier') // compilation error

Instantiation

The simplest way to use the library is to directly construct a TypedContainer:

import { TypedContainer } from '@inversifyjs/strongly-typed';

const container = new TypedContainer<BindingMap>();

This class is actually just a re-typed re-export of the vanilla Container, so shares all underlying functionality.

Type assertion

If you'd prefer to keep this library out of your final dependency tree, you can just import the types and perform a type assertion:

import { Container } from 'inversify';
// The type import will be stripped during transpilation
import type { TypedContainer } from '@inversifyjs/strongly-typed';

const container = new Container() as TypedContainer<BindingMap>;

Injection

The library also exposes a TypedInject type that will leverage the BindingMap you've used to strongly type your Container.

You'll need to re-export the inject decorator with a type assertion:

import { inject, multiInject } from 'inversify';
import type { TypedInject, TypedMultiInject } from '@inversifyjs/strongly-typed';

export const $inject = inject as TypedInject<BindingMap>;
export const $multiInject = multiInject as TypedMultiInject<BindingMap>;

You can now use this to strongly type injected constructor parameters, or public properties:

@injectable()
class B {
  public constructor(
    @$inject('foo') // ok
    foo: Foo,

    @$inject('foo') // compilation error
    bar: Bar,
  ) {}
}

@injectable()
class A {
  @$inject('foo') // ok
  public foo: Foo;

  @$inject('foo') // compilation error
  public bar: Bar;
}

Advanced usage

Promise bindings

inversify allows binding Promises, but these must be retrieved using getAsync() trying to resolve them using get() will throw.

The type signatures will help to enforce this if you show an async binding in the binding map with a Promise:

interface BindingMap {
  number: number;
  asyncNumber: Promise<number>;
}

const container = new TypedContainer<BindingMap>();

container.get('number') // number
container.get('asyncNumber') // compiler error
container.getAsync('asyncNumber') // Promise<number>

Container hierarchies

A strongly-typed child container can be created from a parent container.

This strong typing is optional for the child:

const parent = new TypedContainer<BindingMap>();
const child = parent.createChild(); // weakly typed

If the child is strongly-typed, its binding will automatically be adjusted to include the parent types:

const parent = new TypedContainer<{foo: Foo}>();
const child = parent.createChild<{bar: Bar}>();
child.get('bar') // ok
child.get('foo') // ok

A child may also override a parent's bindings with a completely unrelated type:

const parent = new TypedContainer<{foo: Foo}>();
const child = parent.createChild<{foo: Bar}>();
const resolved: Bar = child.get('foo');

Known issues / limitations

Strongly-typing private properties

Note that because the decorator types can't "see" private properties, we can't strongly type them:

@injectable()
class A {
  @$inject('foo')
  private foo: Foo; // fails :'(
}

Work around this by either:

  1. Making the property public (and perhaps prefixing it with an underscore to remind consumers it should be private)
  2. Using the weakly-typed @inject() directly from 'inversify'

Confusing compiler errors for constructor injection

There's no custom compiler errors for TypeScript, so we can't signal particularly usefully that a constructor parameter is wrong, apart from the fact that the compilation fails.

The error will look something like:

Unable to resolve signature of parameter decorator when called as an expression.
  Argument of type '2' is not assignable to parameter of type 'undefined'. (ts1239)

This actually means something like this:

The injected constructor parameter at index 2 is of the wrong type.