Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript - use correct version of setTimeout (node vs window)

People also ask

What is the difference between setTimeout and window setTimeout?

It is exactly the same. Window is implicit if you don't specify it. Check out possible duplicate: Is there a need to prepend setTimeout and setInterval with window object?

Does setTimeout affect performance?

No significant effect at all, setTimeout runs in an event loop, it doesn't block or harm execution.

Can you use setTimeout in node?

The setTimeout function is used to call a function after the specified number of milliseconds. The delay of the called function begins after the remaining statements in the script have finished executing. The setTimeout function is found in the Timers module of Node. js.


let timer: ReturnType<typeof setTimeout> = setTimeout(() => { ... });

clearTimeout(timer);

By using ReturnType<fn> you are getting independence from platform. You won't be forced to use neither any nor window.setTimeout which will break if you run the code on nodeJS server (eg. server-side rendered page).


Good news, this is also compatible with Deno!


2021 update

Akxe's answer suggests ReturnType<Type> technique introduced in Typescript 2.3:

let n: ReturnType<typeof setTimeout>;
n = setTimeout(cb, 500);

It is nice and seems to be preferred over explicit casting. But the result type of "n" in this case is "NodeJS.Timeout", and it is possible to use it as follows:

let n: NodeJS.Timeout;
n = setTimeout(cb, 500);

The only problem with ReturnType/NodeJS.Timeout approach is that numeric operations in browser-specific environment still require casting:

if ((n as unknown as number) % 2 === 0) {
  clearTimeout(n);
}

Original answer

A workaround that does not affect variable declaration:

let n: number;
n = setTimeout(function () { /* snip */  }, 500) as unknown as number;

Also, in browser-specific environment it is possible to use window object with no casting:

let n: number;
n = window.setTimeout(function () { /* snip */  }, 500);

I guess it depends on where you will be running your code.

If your runtime target is server side Node JS, use:

let timeout: NodeJS.Timeout;
global.clearTimeout(timeout);

If your runtime target is a browser, use:

let timeout: number;
window.clearTimeout(timeout);

This will likely work with older versions, but with TypeScript version ^3.5.3 and Node.js version ^10.15.3, you should be able to import the Node-specific functions from the Timers module, i.e.:

import { setTimeout } from 'timers';

That will return an instance of Timeout of type NodeJS.Timeout that you can pass to clearTimeout:

import { clearTimeout, setTimeout } from 'timers';

const timeout: NodeJS.Timeout = setTimeout(function () { /* snip */  }, 500);

clearTimeout(timeout);

This works perfectly well for me.

type Timer = ReturnType<typeof setTimeout>

const timer: Timer = setTimeout(() => {}, 1000)

If you're targeting setInterval of window. Then you can also write it as

let timerId: number = setInterval((()=>{
    this.populateGrid(true)
  }) as TimerHandler, 5*1000)
}