Las funciones en TypeScript son mucho más que simples bloques de código; son elementos de primera clase, lo que significa que podemos tratarlas como cualquier otra variable o dato. Esto nos permite asignar funciones a variables, pasarlas como argumentos y devolverlas desde otras funciones, lo que abre un abanico enorme de posibilidades para escribir código flexible y reutilizable.
Cuando declaramos una función con un nombre, como sumar, le estamos asignando un identificador con un tipo específico que representa esa función. Pero también podemos crear funciones anónimas y asignarlas directamente a variables. Por ejemplo, podemos declarar una variable llamada restar y asignarle una función que reciba dos parámetros de tipo number y devuelva su resta:
const restar = function(m: number, n: number): number {
console.log('Ejecutando resta');
return m - n;
};
console.log(restar(5, 4)); // 1
Aquí, TypeScript infiere el tipo de restar como una función que recibe dos números y devuelve un número. Para que quede más claro, podemos declarar explícitamente el tipo de la variable restar:
const restar: (m: number, n: number) => number = function(m, n) {
console.log('Ejecutando resta');
return m - n;
};
Esta sintaxis, aunque un poco particular, es muy común cuando trabajamos con funciones que reciben otras funciones como parámetros, como los callbacks. Por ejemplo, podemos declarar una función multiplicar con un tipo específico, pero sin asignarle inmediatamente una implementación:
let multiplicar: (m: number, n: number) => number;
Luego, podemos asignarle una función sin necesidad de volver a especificar los tipos de los parámetros, ya que TypeScript los infiere automáticamente:
multiplicar = function(m, n) {
return m * n;
};
console.log(multiplicar(4, 3)); // 12
También podemos usar la sintaxis de arrow functions para hacer el código más conciso:
multiplicar = (m, n) => m * n;
Esta capacidad de inferencia es especialmente útil cuando trabajamos con callbacks. Por ejemplo, imaginemos que queremos crear una función que reciba dos números y una función callback que procese el resultado de multiplicarlos. Podríamos definirla así:
function multiplicarConCallback(
a: number,
b: number,
callback: (result: number) => void
): void {
const resultado = a * b;
callback(resultado);
}
Al llamar a esta función, podemos pasarle una función anónima que reciba el resultado y lo imprima:
multiplicarConCallback(4, 5, (resultado) => {
console.log(`El resultado es ${resultado}`);
});
En este ejemplo, TypeScript sabe que el parámetro resultado dentro del callback es un number, por lo que podemos usar métodos propios de los números, como toFixed o toExponential, con autocompletado y chequeo de tipos.
Este enfoque de tipar funciones que reciben otras funciones como parámetros es muy común en librerías y frameworks, especialmente en aquellas que manejan eventos o código asíncrono. Nos permite escribir código seguro y claro, donde los tipos de los argumentos y retornos están bien definidos y el autocompletado nos ayuda a evitar errores.
Así, TypeScript nos ofrece una forma poderosa y flexible de trabajar con funciones, combinando la libertad de JavaScript con la seguridad y claridad que aporta la tipificación estática.