New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEAT] Add support for optional dependencies #1694
Comments
Hello @derevnjuk Yes the DI isn’t designed to have optional dependencies. I don’t know what is the exact usecase, because dependency always exist if it’s an injected class (tokenProvider===class). And circular dependency musn’t be injected like this (by constructor) and must use The error is a symptom of a circular dependencies, because type isn’t stored by typescript. Adding optional decorator is strange for me. In your example, the bar will never be injected… so what is the interest? That I don’t see ^^ I think isn’t a huge work to solve this but I want to be sure there is a real usecase. See you ;) |
That's not exactly true. Even if you use a decorator on the property, it will raise the same exception.
In this particular case, it has nothing to do with circular dependencies. Once you declare a dependency, deps = deps || Metadata.getParamTypes(provider.useClass); Since you imply that a dependency is optional, you don't register a provider. As a result, // ./src/services/RetryStrategy.ts
export interface RetryStrategy {
acquire<T extends (...args: unknown[]) => unknown>(task: T): Promise<ReturnType<T>>;
}
export const RetryStrategy: unique symbol = Symbol("RetryStrategy");
// ./src/interceptors/TransactionalInterceptor.ts
@Interceptor()
export class TransactionalInterceptor implements InterceptorMethods {
@Inject(RetryStrategy)
private readonly retryStrategy?: RetryStrategy;
constructor(
@Inject() private readonly registry: MikroOrmRegistry,
@Inject() private readonly context: DBContext,
@Inject() private readonly logger: Logger
) {}
// ...
} It provides a user the ability to register a custom implementation of export class ExponentialBackoff implements RetryStrategy {
// ...
}
registerProvider({
provide: RetryStrategy,
useClass: ExponentialBackoff
}); Ofc, we can declare a // ./src/services/RetryStrategy.ts
export interface RetryStrategy {
acquire<T extends (...args: unknown[]) => unknown>(task: T): Promise<ReturnType<T>>;
}
// ./src/services/RetryStrategy.ts
export class NoopRetryStrategy implements RetryStrategy {
// ...
}
// ./src/interceptors/TransactionalInterceptor.ts
@Interceptor()
export class TransactionalInterceptor implements InterceptorMethods {
@Inject()
private readonly retryStrategy: NoopRetryStrategy;
constructor(
@Inject() private readonly registry: MikroOrmRegistry,
@Inject() private readonly context: DBContext,
@Inject() private readonly logger: Logger
) {}
// ...
}
@OverrideProvider(NoopRetryStrategy)
export class ExponentialBackoff implements RetryStrategy {
// ...
} |
Haaaaa totally clear :D Thanks for the explanation ^^. I'm ok to add this feature to the backlog! |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Informations
As a user, I would like to use the empty constructor
new Foo()
, to avoid registeringnoop
dependencies if they are not required.The new parameter decorator can be introduced to be used on constructor parameters, which marks the parameter as optional. At the same time, the IoC container should provide
null
orundefined
if the dependency is not found.Currently, while resolving an instance, the IoC container fails with the following error:
However, there is a workaround. You can register a value provider manually like this:
The text was updated successfully, but these errors were encountered: