TypeScript: utilice la versión correcta de setTimeout (nodo frente a ventana)

Resuelto Kevin Tighe asked hace 7 años • 12 respuestas

Estoy trabajando para actualizar un código TypeScript antiguo para usar la última versión del compilador y tengo problemas con una llamada a setTimeout. El código espera llamar a la setTimeoutfunción del navegador que devuelve un número:

setTimeout(handler: (...args: any[]) => void, timeout: number): number;

Sin embargo, el compilador está resolviendo esto en la implementación del nodo, lo que devuelve un NodeJS.Timer:

setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer;

Este código no se ejecuta en el nodo, pero los tipos de nodo se incorporan como una dependencia de otra cosa (no estoy seguro de qué).

¿Cómo puedo indicarle al compilador que elija la versión que setTimeoutquiero?

Aquí está el código en cuestión:

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

Esto produce el error del compilador:

TS2322: El tipo 'Temporizador' no se puede asignar al tipo 'número'.

Kevin Tighe avatar Aug 22 '17 00:08 Kevin Tighe
Aceptado
let timer: ReturnType<typeof setTimeout> = setTimeout(() => { ... });

clearTimeout(timer);

Al usarlo, ReturnType<fn>obtienes independencia de la plataforma. No se verá obligado a usar ninguno anyni window.setTimeoutse romperá si ejecuta el código en el servidor nodeJS (por ejemplo, una página renderizada del lado del servidor).


Buenas noticias, ¡esto también es compatible con Deno!

Akxe avatar May 21 '2019 13:05 Akxe

actualización 2021

La respuesta de Akxe sugiere ReturnType<Type>una técnica introducida en Typecript 2.3:

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

Es agradable y parece preferible al casting explícito. Pero el tipo de resultado de "n" en este caso es "NodeJS.Timeout", y es posible usarlo de la siguiente manera:

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

El único problema con el enfoque ReturnType/NodeJS.Timeout es que las operaciones numéricas en un entorno específico del navegador aún requieren conversión:

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

Respuesta original

Una solución alternativa que no afecta la declaración de variables:

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

Además, en un entorno específico del navegador es posible utilizar windowobjetos sin conversión:

let n: number;
n = window.setTimeout(function () { /* snip */  }, 500);
dhilt avatar May 19 '2018 18:05 dhilt

Supongo que depende de dónde ejecutará su código.

Si su objetivo de tiempo de ejecución es el Nodo JS del lado del servidor, utilice:

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

Si su objetivo de ejecución es un navegador, utilice:

let timeout: number;
window.clearTimeout(timeout);
cwouter avatar Jul 10 '2019 11:07 cwouter