inversify / InversifyJS

A powerful and lightweight inversion of control container for JavaScript & Node.js apps powered by TypeScript.
http://inversify.io/
MIT License
11.02k stars 712 forks source link

feat: strongly-typed `Container` #1575

Open alecgibson opened 3 weeks ago

alecgibson commented 3 weeks ago

Description

This is a non-breaking change, affecting only TypeScript types, and doesn't change the implementation in any way.

Motivation

inversify already has some basic support for types when binding, and retrieving bindings.

However, the type support requires manual intervention from developers, and can be error-prone.

For example, the following code will happily compile, even though the types here are inconsistent:

container.bind<Bar>('bar').to(Bar);
const foo = container.get<Foo>('bar')

Furthermore, this proposal paves the way for type-safe injection, which will be added once this change is in.

Improved type safety

This change adds an optional type parameter to the Container, which takes an identifier map as an argument. For example:

type IdentifierMap = {
  foo: Foo;
  bar: Bar;
};

const container = new Container<IdentifierMap>;

If a Container is typed like this, we now get strong typing both when binding, and getting bindings:

const container = new Container<IdentifierMap>;

container.bind('foo').to(Foo); // ok
container.bind('foo').to(Bar); // error

const foo: Foo = container.get('foo') // ok
const bar: Bar = container.get('foo') // error

This also has the added benefit of no longer needing to pass around service identifier constants: the strings (or symbols) are all strongly typed, and will fail compilation if an incorrect one is used.

Non-breaking

This change aims to make no breaks to the existing types, so any Container without an argument should continue to work as it did before.

Related Issue

https://github.com/inversify/InversifyJS/issues/788

How Has This Been Tested?

Types of changes

Checklist: