
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
fuse-ts is a dependency injection library for
TypeScript. It allows you to use a @fused decorator on your TypeScript classes, so that when an instance
of that class is constructed, it will receive instances of the types the class depends on.
import {fuse, fused} from 'fuse-ts';
class Service {
public someMethod(): void { }
}
class ServiceImplementation implements Service {
public someMethod(): void { }
}
@fused
class ServiceConsumer {
constructor(public service?: Service) { }
}
// let fuse know that all Service dependencies are
// to be instances of ServiceImplementation
fuse(Service).to(ServiceImplementation);
var serviceConsumer: ServiceConsumer = new ServiceConsumer();
// this will be true
var isServiceImplementation: boolean = serviceConsumer.service instanceof ServiceImplementation;
As you can see in the example, the ServiceConsumer constructor has one
optional argument of the type Service. Upon creating an instance by using
new ServiceConsumer(), fuse-ts will for each constructor argument look for a
type that has been "fused" to the type of that argument, inject an instance in
the constructor. So, in the example, a ServiceImplementation instance is
injected in the ServiceConsumer constructor. This is made possible by the
@fused decorator on the ServiceConsumer class.
To use fuse-ts in your project, make sure you use the --experimentalDecorators and --emitDecoratorMetadata flags when running tsc, or use the following in your tsconfig.json file:
{
...
"experimentalDecorators": true,
"emitDecoratorMetadata": true
...
}
When you decorate a TypeScript class with @fused, the class's constructor is wrapped by a function
that resolves values for the original constructor's arguments, based on their type. For convenience, it
is preferable to make all the constructor's arguments you want injected optional, so you can call the
constructor without TypeScript compiler complaints. Like this:
@fused
class Component {
constructor(a?: A, b?: B) {
// stuff
}
}
var component = new Component();
The following won't compile:
@fused
class Component {
constructor(a: A, b: B) {
// stuff
}
}
// Fails with "Supplied parameters do not match any signature of call target."
var component = new Component();
If there are arguments you always want to pass to the constructor (ie. never injected by fuse-ts), make them required:
@fused
class Component {
constructor(value: number, a?: A, b?: B) {
// stuff
}
}
var component = new Component(1);
To make a type injectable, it must be registered with the library. This is done by calling
fuse(BaseType).to(InjectedType). See the following example:
class BaseType {
public someMethod(): void { }
}
class InjectedType implements BaseType {
public someMethod(): void {
// stuff
}
}
// register with fuse-ts
fuse(BaseType).to(InjectedType);
You probably noticed that InjectedType implements a class instead of a TypeScript interface. Since
interfaces are a design-time feature of TypeScript, they are not available in the transpiled JavaScript at
run time. Because of that and the way fuse-ts works (for now), interfaces are unsuitable as a type to
resolve to. So the following won't work:
interface Foo {
fooIt(): void;
}
class InjectedFoo implements Foo {
public fooIt(): void {
// stuff
}
}
// register with fuse-ts
fuse(Foo).to(InjectedFoo); // Compilation fails with "Cannot find name 'Foo'"
When you use fuse(A).to(B), each injected instance of A will resolve to a new instance of B. This is called a transient dependency. This is the default behaviour of fuse-ts. To make this explicit in your code, you can use the asTransient() method on the result of fuse(A).to(B).
An example:
class Service {
public serviceMethod(): void {}
}
class SingletonServiceImplementation implements Service {
public serviceMethod(): void {
// stuff
}
}
fuse(Service).to(SingletonServiceImplementation).asTransient();
@fused
class ServiceConsumer {
constructor(public service?: Service) { }
}
var firstInstance = new ServiceConsumer();
var secondInstance = new ServiceConsumer();
// The following will be true
firstInstance.service !== secondInstance.service;
Sometimes you want a service to be one and the same instance across your whole project, in other words, you want it to be a singleton. By default, each time fuse-ts injects a dependency, an new instance of that dependency is created. To make fuse-ts inject a singleton, you use the following:
class Service {
public serviceMethod(): void {}
}
class SingletonServiceImplementation implements Service {
public serviceMethod(): void {
// stuff
}
}
fuse(Service).to(SingletonServiceImplementation).asSingleton();
Now, each time a class that depends on Service is instantiated, it will receive the same
SingletonServiceImplementation instance:
@fused
class ServiceConsumer {
constructor(public service?: Service) { }
}
var firstInstance = new ServiceConsumer();
var secondInstance = new ServiceConsumer();
// The following will be true
firstInstance.service === secondInstance.service;
This was created as part of a first personal venture into TypeScript, and inspired by the .NET Ninject DI library. Comments and complaints are welcome.
FAQs
Dependency injection for TypeScript
We found that fuse-ts demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.