Search code examples
javascripttypescripttype-safety

How do I replace the setTimeout method in a typesafe manner?


In my tests I want to replace the setTimeout method so that the tests run fast.

Originally I had the equivalent piece of code that used "any"... But of course eslint etc bleats.

I now have this piece of code which at last does not have any in it.

  let defaultTimeout: typeof globalThis.setTimeout;
  beforeEach(() => {
    defaultTimeout = global.setTimeout;
    globalThis.setTimeout = (callback: TimerHandler) => { (1)
      defaultTimeout(callback, 500);
    };
  })

However, I still get an error at globalThis.setTimeout

TS2741: Property  promisify  is missing in type  (callback: TimerHandler) => void  but required in type  typeof setTimeout  timers.d.ts(161, 19):  promisify  is declared here.

I know that I can resolve this by using any and unknown... is there another way?


Solution

  • Overriding functions like setTimeout, setInterval, console.* is bad practice. Why do you do it in that way? Did you consider using timer mocks?

    I assume you use Jest or Vitest, anyway the logic is identical.

    If all you want is to skip the timers, you could do

    jest.useFakeTimers();
    
    // Your test code goes here...
    
    expect(true).toEqual(true);
    
    jest.runAllTimers();
    
    jest.useRealTimers();
    

    The jest.runAllTimers(); line is the one doing the trick, "fast-forwarding" the timers, read more here: https://jestjs.io/docs/jest-object#jestrunalltimers