Consider a method that calculates some ETA:

class Calendar {
  add3WorkingDays(): Date {
    const result = new Date();
    let daysAdded = 0;
    while (daysAdded < 3) {
      result.setDate(result.getDate() + 1);
      if (this.isWorkingDay(result)) {
    return result;

  isWorkingDay(date: Date): boolean {
    const day = date.getDay();
    return day !== 0 && day !== 6;

Notice how add3WorkingDays depends on the time when it’s called (result is initially now). Because of that, you’d have trouble writing reliable unit tests for this.

My recommendation: change the implicit dependency of now to explicit one and inject it:

  add3WorkingDays(date: Date): Date {
    const result = new Date(date);
    // no changes from here

It takes only so much to implement dependency injection, the most overcomplicated technique in the history of programming. You don’t need frameworks, containers, service locators, interfaces, or decorators. You only need to know how to parameterize a method.

Oh, by the way, we changed the interface of the method too. We have to change all the callers: calendar.add3WorkingDays() -> calendar.add3WorkingDays(new Date())

Does this mean you don’t want to introduce dependency injection later in the project, to avoid risky refactors? No. You can still have DI without changing the interface using the default parameter:

  add3WorkingDays(date: Date = new Date())
Continue reading