Fechas en TypeScript: cómo declarar el tipo correctamente y no volverse loco

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué «Date» en TypeScript es una trampa?

\n

Imagina: estás escribiendo una aplicación, todo funciona perfectamente. Pero un buen día llega un reporte de error: «El usuario de Tokio ve la fecha un día antes». Abres el código y ves el clásico: let date: Date = "2024-12-01". O peor aún — any. ¿Te suena familiar?

\n

La pregunta «How do I express a date type in TypeScript?» en Stack Overflow ha acumulado decenas de miles de visitas. Y con razón. Parecería que la respuesta es simple: usa Date. Pero en la práctica es más complicado. TypeScript es una extensión de JavaScript, y Date en JS es un objeto que se comporta... de manera peculiar.

\n

En este artículo no solo analizaremos la sintaxis, sino el tipado correcto de fechas, que salvará tu proyecto de errores, mejorará el rendimiento y hará que el código sea comprensible para el equipo. Aprenderás a trabajar con fechas reales en TypeScript sin perder tiempo en depuración.

\n\n

1. Tipado básico: ¿Date, string o number?

\n

La opción más obvia es el tipo incorporado Date:

\n
let birthday: Date = new Date('1990-05-15');
\n

¿Funciona? Sí. Pero hay un detalle: TypeScript no verifica si la fecha es válida. Puedes escribir new Date('abc') — no habrá error de compilación, pero en tiempo de ejecución obtendrás Invalid Date. Y al intentar llamar a .getTime() devolverá NaN.

\n

Una opción más estricta es usar cadenas en formato ISO 8601:

\n
type ISODateString = string;\nlet eventDate: ISODateString = '2024-12-01T10:00:00Z';
\n

Ventaja: tipo simple, fácil de serializar a JSON. Desventaja: sin validación — puedes asignar 'hello' y TS no dirá nada.

\n

La tercera opción es timestamp (number):

\n
type Timestamp = number;\nlet ms: Timestamp = Date.now();
\n

Ideal para operaciones matemáticas, pero ilegible para humanos. Y de nuevo — cualquier número pasará la verificación.

\n\n

Resumen de tipos básicos

\n

Si necesitas un tipado rápido y sencillo — usa Date. Si trabajas con API — string. Si solo son cálculos — number. Pero para proyectos serios esto no es suficiente. Profundicemos.

\n\n

2. Tipos personalizados y branded types

\n

Para que TypeScript no confunda una cadena de fecha con una cadena normal, se usan branded types. Es como una etiqueta que dice «Soy una fecha, ¡verificado!»:

\n
type DateString = string & { __brand: 'DateString' };\n\nfunction toDateString(date: Date): DateString {\n    return date.toISOString() as DateString;\n}\n\nfunction processDate(d: DateString) {\n    // aquí d es definitivamente una cadena ISO\n}\n\nconst iso = toDateString(new Date());\nprocessDate(iso); // OK\n// processDate('hello'); // ❌ ¡Error!
\n

Esto agrega seguridad en tiempo de compilación. El costo es un poco más de código. Pero para proyectos grandes (especialmente si tienes microservicios o API REST) es el estándar de oro.

\n\n

3. Librerías para trabajar con fechas en TypeScript

\n

El Date nativo es malo. Es mutable, analiza cadenas de forma inconsistente, y las zonas horarias son un dolor aparte. Por eso en proyectos reales se usan librerías. Aquí hay tres favoritas:

\n\n

3.1. date-fns (ligera y modular)

\n
import { format, parseISO } from 'date-fns';\n\nconst date: Date = parseISO('2024-12-01T10:00:00Z');\nconst formatted: string = format(date, 'dd.MM.yyyy');
\n

Ventaja: tree-shaking, inmutable (devuelve nuevas fechas), excelente tipado.

\n\n

3.2. Day.js (minimalista)

\n
import dayjs, { Dayjs } from 'dayjs';\n\nconst now: Dayjs = dayjs();\nconst formatted: string = now.format('DD.MM.YYYY');
\n

Day.js es como Moment.js, pero sin el bundle pesado. El tipo Dayjs es un envoltorio que es fácil de pasar entre funciones.

\n\n

3.3. Luxon (

Blogs

Book Recommendations