ProgrammationDéveloppeur Full Stack

Décrivez comment fonctionne la typage Date et les erreurs temporelles en TypeScript. Comment décrire des types corrects pour le travail avec des dates et des heures, et quels problèmes peuvent survenir lors de l'intégration avec des bibliothèques externes ou le Date natif ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Historique de la question :

Dans JavaScript, l'objet Date est utilisé pour représenter des dates et des heures et est connu pour sa spécificité de fonctionnement — mutabilité, complexité d'analyse et particularités des fuseaux horaires. TypeScript utilise pour Date les types JS standards, cependant, la typage et le travail avec des dates dans un code strict nécessitent une approche particulière.

Problème :

Date en JavaScript est un objet mutable qui peut créer des erreurs atypiques (par exemple, setMonth() muter l'objet lui-même, ce qui peut entraîner un comportement inattendu du code). De plus, l'intégration avec des bibliothèques externes (moment.js, date-fns, Day.js, etc.) nécessite de maintenir la précision des types — par exemple, moment.Instant ou des conteneurs de temps spécifiques, incompatibles entre eux. Parfois, le type renvoyé peut être string ou number (timestamp), ce qui entraîne des erreurs lors de l'annotation des types ou de l'utilisation de l'API.

Solution :

TypeScript typise une nouvelle instance Date comme Date, et toutes ses méthodes sont disponibles. Lors de l'intégration avec d'autres bibliothèques, il est important de surveiller attentivement les types des valeurs d'entrée et de sortie — utiliser une conversion explicite en Date (par exemple, new Date(value)), ou créer des types-containers personnalisés pour la date et l'heure. Pour la conversion entre timestamp (number), chaîne et objet Date, il est nécessaire de spécifier strictement les types et de décrire les fonctions avec des types ou des interfaces.

Exemple de code :

function toIsoString(d: Date | number | string): string { if (d instanceof Date) return d.toISOString(); if (typeof d === 'number' || typeof d === 'string') return new Date(d).toISOString(); throw new Error('Date invalide'); }

Caractéristiques clés :

  • Date — objet mutable, pas un type value, mais un type reference.
  • La réception et le retour de dates depuis l'API ou des bibliothèques tierces nécessitent de maintenir strictement la compatibilité des types.
  • Les wrappers externes tels que moment, dayjs nécessitent des types personnalisés explicites et/ou des fonctions de type guard.

Questions pièges.

Le type "Date" en TypeScript est-il un simple type value ?

Non, Date est un objet, c'est-à-dire un type référence. La comparaison des dates via == ou === ne compare pas les valeurs, uniquement les références.

const d1 = new Date('2022-01-01'); const d2 = new Date('2022-01-01'); d1 === d2; // false

Peut-on directement affecter une chaîne ou un nombre au type Date sans nouvelle initialisation ?

Non, le type Date n'est pas compatible avec number ou string. Il est nécessaire de créer une nouvelle instance : new Date(value).

const d: Date = new Date('2020-01-01'); // const d2: Date = '2020-01-01'; // Erreur de typage

La fonction prenant Date fonctionnera-t-elle avec des objets de bibliothèques externes (moment, dayjs) ?

Non, à moins que la bibliothèque n'implémente explicitement la conversion/compatibilité avec Date via valueOf/toDate, ce sont des types différents, et TypeScript ne les comprendra pas comme Date.

import dayjs from "dayjs"; function doSomething(d: Date) { /* ... */ } doSomething(dayjs()); // Erreur, car le type Dayjs n'est pas compatible avec Date

Erreurs typiques et anti-patterns

  • Utilisation de tout type (any) pour la date lors de l'intégration avec l'API.
  • Mutation de l'objet Date (set*, setUTC*) lors de son passage dans plusieurs fonctions — risque de condition de course.
  • Incompatibilité des types : tentative de travailler avec un type externe comme s'il s'agissait de Date.

Exemple de la vie réelle

Cas négatif

Le code acceptait l'argument comme any, et supposait ensuite que c'était une Date. En pratique, l'API renvoyait un timestamp en chaîne, ce qui entraînait une erreur lors de l'appel à .getFullYear().

Avantages :

  • Fonctionnement "dans tous les sens" sans erreurs de compilation.

Inconvénients :

  • Risque d'erreurs à l'exécution.
  • Difficultés pour capturer des bugs en production.

Cas positif

Le développeur a créé un type explicite pour le paramètre (Date | string | number), a introduit un type guard, et la fonction appelait new Date de manière explicite. Le compilateur force à traiter explicitement tous les types.

Avantages :

  • Erreurs transparentes dès la phase de compilation.
  • Fonctionnement plus fiable avec différents types de date d'entrée.

Inconvénients :

  • Un peu plus de code générique (type guards).
  • Nécessite de se plonger dans les types des bibliothèques externes.