ProgramaciónDesarrollador TypeScript

¿Cómo implementar y tipificar correctamente la sobrecarga (overload) de funciones en TypeScript a nivel de firmas? ¿Por qué no se pueden usar varios cuerpos de función y qué sucede con los tipos de parámetros dentro del cuerpo de la función? Proporcione escenarios prácticos de uso y los errores más comunes.

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

La sobrecarga de funciones permite crear una única función con diferentes variantes de parámetros aceptados y valor de retorno. En otros lenguajes, como C# o Java, se pueden describir varias funciones con el mismo nombre, pero con diferentes tipos o cantidades de argumentos. TypeScript acerca este mecanismo a través de la sobrecarga de firmas a nivel de tipos, pero el cuerpo de la función siempre es uno.

La historia del problema es que en JavaScript no hay soporte nativo para la sobrecarga por tipo o cantidad de parámetros. Con la llegada de TypeScript, la sobrecarga se emula mediante la declaración de varias firmas de función de forma consecutiva y una única implementación, dentro de la cual se distingue manualmente con qué tipo se está trabajando actualmente.

El problema surge si no se mantiene la correspondencia con las firmas declaradas: a los parámetros dentro del cuerpo de la función, TypeScript les asigna el tipo más general (la unión de todos los tipos de parámetros) y el programador debe realizar comprobaciones y type guards.

Solución: Tipificar estrictamente las sobrecargas en las firmas explícitas, trabajar adecuadamente con tipos de unión y type guards, y documentar correctamente el comportamiento.

Ejemplo de código:

function format(value: string): string; function format(value: number, locale: string): string; function format(value: any, locale?: string): string { if (typeof value === 'number') { return value.toLocaleString(locale); } return value.trim(); } format(' hello '); // 'hello' format(123456, 'ru-RU'); // '123 456'

Características clave:

  • Varias firmas de sobrecarga consecutivas, una implementación debajo de ellas.
  • Para trabajar con los parámetros en el cuerpo, se utiliza tipo unión o any/unknown.
  • El tipo del cuerpo es más amplio/universal que las firmas en la parte superior.

Preguntas engañosas.

¿Se pueden declarar varias funciones con el mismo nombre y diferentes cuerpos, como en C#?

No. En TypeScript (y JavaScript) de hecho, solo existe una función con ese nombre. Las sobrecargas funcionan solo a nivel de tipos para el compilador, pero hay solo un cuerpo de función.

¿Qué pasará si no se implementa la firma con los parámetros más generales después de las firmas de sobrecarga?

TypeScript generará un error de compilación. Siempre debe haber una función de implementación cuyos parámetros cubran todas las posibles variantes de sobrecarga.

function foo(a: string): string; function foo(a: number): number; // falta el cuerpo — error

¿Puedo usar dentro del cuerpo propiedades específicas de una firma concreta?

No, solo después de una comprobación de tipo (type guard) o un casting de tipo. De lo contrario, TypeScript no permitirá utilizar estas propiedades directamente, ya que no se sabe a qué firma se está llamando actualmente.

function bar(x: string): number; function bar(x: number): number; function bar(x: string | number): number { if (typeof x === 'string') return x.length; return x * 2; }

Errores típicos y anti-patrón.

  • No añaden implementación después de las firmas de sobrecarga — la compilación fallará.
  • Usan propiedades específicas en el cuerpo de la función sin comprobación de tipo.
  • Complican demasiado las sobrecargas, llevando a un código poco legible.
  • No describen explícitamente los tipos devueltos o se olvidan de actualizar las firmas al cambiar la lógica de la función.

Ejemplo de la vida real

Caso negativo

Se olvidaron de agregar la firma universal de implementación:

function sum(a: string, b: string): string; function sum(a: number, b: number): number; // no hay implementación — el compilador se queja

Ventajas:

  • La idea de describir una API conveniente

Desventajas:

  • El código no compila, no se puede manejar ninguna variante

Caso positivo

Implementan la sobrecarga de acuerdo al estándar:

function sum(a: string, b: string): string; function sum(a: number, b: number): number; function sum(a: any, b: any): any { return typeof a === 'string' && typeof b === 'string' ? a + b : a + b; }

Ventajas:

  • Todas las variantes se manejan correctamente, los tipos se inferirán en el momento de la compilación

Desventajas:

  • El cuerpo de la función requiere control manual de tipos, no se puede olvidar comprobar cada variante