Issue
I've got a DI container class which requires the classes to resolve to be decorated with an @Injectable()
decorator, in order for the decorated class to emit metadata and for further configuration (pretty much like Angular DI works, https://angular.io/guide/dependency-injection).
In order to register third-party classes to my container I need to apply the @Injectable
decorator to classes which I'm not able to modify. Think of something like a logger library installed in node_modules which I'd like to have in my container.
Is there a way to apply decorators to third-party classes? I'm thinking of something like:
import {Container, Injectable} from "./Container";
import {Logger} from "@vendor/logger";
const container = new Container();
container.register(Logger, { useClass: Logger }); // not possible, since Logger is not decorated
container.register(decorate(Logger, Injectable), { useClass: Logger }); // something like this, which would allow for decorating a class with a certain decorator
The only solution I can think of now is to create a decorated proxy class which extends from the real logger class. But proxying all third party classes seems like a lot of overhead.
Any other ideas?
Edit to give some more information:
The @Injectable
decorator is required because non-decorated classes do not emit metadata (which would make it impossible for the container to read and resolve its dependencies). It's simply implemented by adding a metadata key to the decorated class with a key of __INJECTABLE
and a value of true
- whenever new services are registered in the container it checks if the __INJECTABLE
flag is set and throws an error otherwise.
Here's an example of a proxy class:
import {Container, Injectable} from "./Container";
import {Logger as ParentLogger} from "@vendor/logger";
// Proxy
@Injectable()
class Logger extends ParentLogger {
}
const container = new Container();
container.register(Logger, { useClass: Logger });
This should work I guess, but would require to create proxies for pretty much every third party class.
Solution
Your decorate
function can look something like this:
function Injectable() { return (_: any) => {} }
class ParentLogger { }
// Proxy
@Injectable()
class Logger extends ParentLogger {
}
function decorate<T extends { new(...args: any[]): any }>(sourceClass: T): T{
@Injectable()
class destinationClass extends sourceClass
{
constructor(...args: any[]) {
super(...args);
}
}
return destinationClass;
}
const DecoratedLogger = decorate(ParentLogger);
Playground here.
Answered By - Tiberiu Maran
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.