Constructor Injection
Inject dependencies through constructors cleanly.
Constructor Injection is a free TypeScript Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the TypeScript Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Constructor Injection in Depth
Constructor injection declares every dependency as a constructor parameter. The object is fully wired the moment it exists, which makes required collaborators impossible to forget.
Parameter Properties
TypeScript can declare and assign a dependency in one step using an access modifier on the parameter. private readonly creates and assigns the field automatically.
interface Mailer { send(to: string, body: string): void; }
class Notifier {
constructor(private readonly mailer: Mailer) {}
}Interface-Based Dependencies
Depending on an interface rather than a class decouples the consumer from any specific implementation. Any object matching the interface can be supplied.
interface Mailer { send(to: string, body: string): void; }
class SmtpMailer implements Mailer {
send(to: string, body: string) { console.log("SMTP ->", to); }
}Wiring at the Composition Root
The place that creates the object graph is the composition root. There you pick concrete implementations and inject them.
class Notifier {
constructor(private readonly mailer: Mailer) {}
notify(to: string) { this.mailer.send(to, "hello"); }
}
const app = new Notifier(new SmtpMailer());
app.notify("a@b.com");Swapping Implementations
Because the dependency is an interface, you can supply a totally different implementation without touching Notifier. This is the core flexibility DI provides.
class FakeMailer implements Mailer {
sent: string[] = [];
send(to: string) { this.sent.push(to); }
}
const fake = new FakeMailer();
new Notifier(fake).notify("x@y.com");
console.log(fake.sent); // ["x@y.com"]Testing Without Real I/O
Injecting the fake mailer lets a test assert what would have been sent, with no real email. The test is fast, deterministic, and isolated.
const fake = new FakeMailer();
new Notifier(fake).notify("test@site");
console.log(fake.sent.length === 1); // trueMultiple Dependencies
List as many dependencies as needed. Each is explicit, typed, and required, which keeps the class's needs visible at a glance.
interface Logger { log(m: string): void; }
class Notifier {
constructor(
private readonly mailer: Mailer,
private readonly logger: Logger,
) {}
}readonly Prevents Reassignment
Marking injected fields readonly stops them from being swapped mid-life, keeping the object's collaborators stable and predictable.
class Notifier {
constructor(private readonly mailer: Mailer) {}
// this.mailer = ... would be a compile error
}No Hidden new Inside
A class using constructor injection should not new up its collaborators internally. All dependencies arrive through the constructor, keeping coupling explicit.
Required vs Optional
Required dependencies belong in the constructor. Truly optional ones can default to a no-op implementation, still passed in rather than constructed inside.
const noopLogger: Logger = { log() {} };
new Notifier(new SmtpMailer(), noopLogger);Benefits Summary
Constructor injection makes dependencies explicit, objects fully initialized, implementations swappable, and tests trivial. It is the default DI style for good reason.
Quick Check
Quick check on this lesson.
Recap
Constructor injection declares dependencies as parameters (often private readonly) typed by interface. The composition root picks implementations; tests pass fakes. Objects are always fully wired, and collaborators are swappable without editing the class.
Frequently asked questions
Is the “Constructor Injection” lesson free?
Yes — the full text of “Constructor Injection” is free to read here on the web, and the TypeScript Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the TypeScript Academy course, upgrade to CoddyKit PRO.
What will I learn in “Constructor Injection”?
Inject dependencies through constructors cleanly. You practise TypeScript Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start TypeScript Academy?
No prior experience is required. TypeScript Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Constructor Injection” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this TypeScript Academy lesson?
Yes. Every TypeScript Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Inversion of Control Basics
- Constructor Injection
- DI Containers with InversifyJS
- Type-Safe Service Tokens