Historia de la pregunta: En JavaScript, las funciones callback se utilizan en todas partes, pero sus firmas a menudo no son evidentes. En TypeScript, es importante especificar explícitamente los tipos de los parámetros y el valor de retorno, de lo contrario, es fácil tener agujeros en la seguridad de tipos.
Problema: Una tipificación incorrecta o laxa de los callbacks lleva a tipos indefinidos de argumentos y resultados, complica el trabajo con el contexto (this), rompe la verificación automática de errores por parte del compilador y dificulta la refactorización.
Solución: Es necesario definir explícitamente el tipo de la función callback, especificar los tipos de los parámetros pasados, manejar correctamente los argumentos opcionales y el valor de retorno, y si es necesario, fijar explícitamente el tipo del contexto.
Ejemplo de código:
type Callback = (error: Error | null, result?: string) => void; function doAsyncWork(data: string, cb: Callback): void { setTimeout(() => { if (data === '') cb(new Error('Cadena vacía')); else cb(null, data.toUpperCase()); }, 100); }
Características clave:
¿Qué sucede si no se especifica el tipo de retorno del callback?
TypeScript aceptará cualquier tipo de retorno (por ejemplo, undefined, void, Promise), lo que puede llevar a sorpresas en cadenas asíncronas o al devolver valores "por defecto".
type BadCallback = (data: string) => any; // cualquier resultado, falta de control
¿Se puede escribir callback como Function o (...args: any[]) => any?
No se puede. Esto elimina toda la protección de tipos, se pierde información sobre la cantidad de parámetros, sus tipos y el tipo de retorno. Este enfoque resulta más costoso que renunciar completamente a TypeScript.
¿Cómo tipar una función con contexto this?
Utilice el primer parámetro this en la firma de la función o haga un casting a través de bind. Por ejemplo:
interface ClickCallback { (this: HTMLElement, event: MouseEvent): void; } const handler: ClickCallback = function (event) { this.textContent = 'ok'; };
En un proyecto, el callback fue declarado como (...args: any[]) => any. Al actualizar la lógica de negocio, la firma cambió, el callback dejó de pasar los argumentos necesarios, los errores solo aparecieron en producción.
Ventajas:
Desventajas:
Se implementaron tipos estrictos: se describieron las interfaces de los callbacks, se comenzó a especificar explícitamente el tipo de this y el tipo de retorno. El compilador comenzó a capturar errores antes del despliegue, se simplificó la refactorización y el soporte para arreglos de errores.
Ventajas:
Desventajas: