TypeScript: utilice la versión correcta de setTimeout (nodo frente a ventana)
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 setTimeout
funció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 setTimeout
quiero?
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'.
let timer: ReturnType<typeof setTimeout> = setTimeout(() => { ... });
clearTimeout(timer);
Al usarlo, ReturnType<fn>
obtienes independencia de la plataforma. No se verá obligado a usar ninguno any
ni window.setTimeout
se 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!
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 window
objetos sin conversión:
let n: number;
n = window.setTimeout(function () { /* snip */ }, 500);
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);