Funciones en TypeScript: tipado de parámetros, retorno y overloads

Las funciones son el bloque de construcción principal de cualquier programa TypeScript. Tiparlas bien implica anotar los parámetros, decidir cuándo anotar el tipo de retorno y conocer los mecanismos para modelar funciones con firmas complejas: parámetros opcionales, valores por defecto, rest params y overloads.

Parámetros y tipo de retorno

TypeScript puede inferir el tipo de retorno de una función a partir de lo que devuelve, pero anotar el tipo explícitamente tiene ventajas: documenta la intención y hace que el error aparezca en la función, no en quien la llama:

// TypeScript infiere number como retorno
function sumar(a: number, b: number) {
  return a + b;
}

// Anotación explícita: recomendable en funciones exportadas
function dividir(a: number, b: number): number {
  if (b === 0) throw new Error("División por cero");
  return a / b;
}

Parámetros opcionales y valores por defecto

Un parámetro opcional se marca con ? y tiene tipo T | undefined dentro del cuerpo. Un parámetro con valor por defecto no necesita ?: TypeScript infiere que es opcional automáticamente:

function saludar(nombre: string, saludo?: string): string {
  return `${saludo ?? "Hola"}, ${nombre}`;
}

// Equivalente con valor por defecto (más limpio)
function saludar(nombre: string, saludo = "Hola"): string {
  return `${saludo}, ${nombre}`;
}

saludar("Ana");            // "Hola, Ana"
saludar("Ana", "Buenos días"); // "Buenos días, Ana"

Los parámetros opcionales deben ir siempre al final de la lista. TypeScript dará error si pones un parámetro requerido después de uno opcional.

Rest params

Los rest params capturan un número variable de argumentos en un array. Se anotan con el tipo de los elementos del array:

function concatenar(separador: string, ...partes: string[]): string {
  return partes.join(separador);
}

concatenar(", ", "uno", "dos", "tres"); // "uno, dos, tres"

Alias de tipos de función

Cuando el mismo tipo de función aparece en varios sitios, un type alias evita repeticiones y mejora la legibilidad:

type Transformador = (valor: T) => T;

function aplicar(valor: T, fn: Transformador): T {
  return fn(valor);
}

const doble: Transformador = (n) => n * 2;
aplicar(5, doble); // 10

Function overloads: varias firmas, una implementación

Los overloads permiten que una función acepte combinaciones distintas de parámetros con tipos de retorno distintos. Se declaran las firmas posibles y luego una implementación más general que las cubre todas:

function formatear(valor: number): string;
function formatear(valor: string): string;
function formatear(valor: number[]): string;
function formatear(valor: number | string | number[]): string {
  if (Array.isArray(valor)) return valor.join(", ");
  if (typeof valor === "number") return valor.toFixed(2);
  return valor.trim();
}

formatear(3.14159);      // "3.14"
formatear("  hola  ");  // "hola"
formatear([1, 2, 3]);    // "1, 2, 3"

La implementación (la última definición, con el tipo union) no es visible para quien llama a la función. Solo se ven las firmas de overload. Usa overloads cuando los tipos de retorno varían según los parámetros de entrada; si el tipo de retorno siempre es el mismo, un union en el parámetro es más simple.

void vs undefined como tipo de retorno

void en el tipo de retorno significa que el valor no se va a usar. undefined significa que la función devuelve exactamente undefined. La diferencia importa en callbacks:

// Este callback tiene tipo de retorno void en forEach,
// pero puede devolver un número sin error:
[1, 2, 3].forEach((n) => n * 2);

// Esta función debe devolver undefined explícitamente:
function nada(): undefined {
  return undefined;
}

Para la mayoría de funciones que no devuelven un valor, void es el tipo correcto. Usa undefined solo cuando necesitas ser preciso sobre el valor exacto devuelto.

Imagen: Pexels / Markus Spiske

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP