There are several ways you can approach this situation.
A) Implementing the Configuration Injection
constructor(
@inject(TYPES.TemplateEngine) templateEngine: TemplateEngineInterface,
@inject(TYPES.MailerConfig) @named("host") host: string,
@inject(TYPES.MailerConfig) @named("port") port: number,
@inject(TYPES.MailerConfig) @named("secure") secure: boolean,
@inject(TYPES.MailerConfig) @named("username") username: string,
@inject(TYPES.MailerConfig) @named("password") password: string
) {
The defined type is:
const TYPES = { MailerConfig: Symbol.for("MailerConfig") }
Here are the corresponding bindings:
type MailerConfig = string|boolean|number;
container.bind<MailerConfig>(TYPES.MailerConfig)
.toConstantValue("localhost")
.whenTargetNamed("host");
container.bind<MailerConfig>(TYPES.MailerConfig)
.toConstantValue(2525)
.whenTargetNamed("port");
container.bind<MailerConfig>(TYPES.MailerConfig)
.toConstantValue(true)
.whenTargetNamed("secure");
container.bind<MailerConfig>(TYPES.MailerConfig)
.toConstantValue("root")
.whenTargetNamed("username");
container.bind<MailerConfig>(TYPES.MailerConfig)
.toConstantValue("toor")
.whenTargetNamed("password");
Additional Tip: Simplifying the Process
To streamline this task, consider creating helper functions to minimize the repetitive steps required.
Bindings
type MailerConfig = string|boolean|number;
const bindMailerConfig = (ctr: Container, key: string, val: MailerConfig) =>
ctr.bind<MailerConfig>(TYPES.MailerConfig)
.toConstantValue(key)
.whenTargetNamed(val);
bindMailerConfig(container, "localhost", "host");
bindMailerConfig(container, 2525, "port");
bindMailerConfig(container, true, "secure");
bindMailerConfig(container, "root", "username");
bindMailerConfig(container,"toor", "password");
Decorators
const injectNamed = (typeId: any) => (name: string) =>
(target: any, targetKey: string, index?: number) => {
inject(typeId)(target, targetKey, number);
named(name)(target, targetKey, number);
};
const injectMailerConfig = injectNamed(TYPES.TemplateEngine);
constructor(
@inject(TYPES.TemplateEngine) templateEngine: TemplateEngineInterface,
@injectMailerConfig("host") host: string,
@injectMailerConfig("port") port: number,
@injectMailerConfig("secure") secure: boolean,
@injectMailerConfig("username") username: string,
@injectMailerConfig("password") password: string
) {
B) Multi-step Initialization Approach
@injectable()
export class NodeMailer implements MailerInterface {
private transporter: any;
private templateEngine: TemplateEngineInterface;
constructor(
@inject(TYPES.TemplateEngine) templateEngine: TemplateEngineInterface,
) {
this.templateEngine = templateEngine;
this.transporter = null;
}
public initialize(host, port, secure, username, password) {
if (this.transporter) {
return this.transporter;
}
this.transporter = nodemailer.createTransport({
host: host,
port: port,
secure: secure,
auth: {
user: username,
pass: password
}
});
return this.transporter;
}
public send() {
if (this.transporter === null) {
throw new Error("You must invoke initialize!");
}
// ...
}
}
This multi-step initialization strategy can align well with a factory mechanism.