0

I have a countdown timer class which can be paused/resumed until the timer hits zero. When the timer expires, a callback function (supplied in the class's constructor) should be invoked. The problem is that when I call this.timeout(), I get an error which says TypeError: this.timeout is not a function.

This is my CountdownTimer class.

export class CountdownTimer implements ICountdownTimer {
  private startTime: number;
  private timeRemaining: number;
  private handle: NodeJS.Timeout;
  private expired: boolean;

  constructor(
    minutes: number,
    seconds: number,
    private readonly increment: number,
    private readonly timeout: () => void,
  ) {
    this.timeRemaining = minutes * 60 * 1000 + seconds * 1000;
    this.expired = false;
  }

  start(): void {
    this.resume();
  }

  pause(): void {
    this.timeRemaining = Date.now() - this.startTime + this.increment * 1000;
    this.clearTimeout();
  }

  resume(): void {
    if (!this.expired) {
      this.startTime = Date.now();
      this.handle = setTimeout(this.onTimeout, this.timeRemaining);
    }
  }

  private onTimeout(): void {
    this.expired = true;
    this.timeout(); // <-- Error here, 'TypeError: this.timeout is not a function'
    this.clearTimeout();
  }

  private clearTimeout(): void {
    clearTimeout(this.handle);
  }
}

I call this code with the following:

const timer = new CountdownTimer(0, 5, 0, () => {
  console.log('Hello!');
});
timer.start();
Marlon
  • 19,924
  • 12
  • 70
  • 101

1 Answers1

1

The problem is setTimeout is calling this.onTimeout but not binded to correct this.

Rewrite this line: this.handle = setTimeout(this.onTimeout, this.timeRemaining); as:

  this.handle = setTimeout(this.onTimeout.bind(this), this.timeRemaining);

Or define onTimeout as a class property for it to always get called with class's this.

  private onTimeout = (): void => {
    this.expired = true;
    this.timeout(); // <-- Error here, 'TypeError: this.timeout is not a function'
    this.clearTimeout();
  }
aleksxor
  • 7,535
  • 1
  • 22
  • 27