Partie 1 : Démarrer un projet sur de bonnes bases
Partie 2 : Construire un espace membre sécurisé avec JWT
Partie 3 : Implémenter des fonctionnalités métiers
Partie 4 : Bonus

5.3. L’entité Workday

Maintenant, nous pouvons passer à notre dernière entité. La particularité de cette entité, c’est qu’elle fait le lien entre nos utilisateurs et leurs tâches. Nous allons voir comment modéliser ces relations dans notre classe. L’entité modélisant une journée de travail, se trouve dans le fichier workday.ts :

import { Task } from './task';
 
export class Workday {
 readonly id: string; // identifiant de la journée de travail
 dueDate: number; // date à laquelle est prévue la journée de travail
 notes?: string; // facultatif : notes éventuelles prises par l’utilisateur
 tasks: Task[]; // la liste des tâches à faire
 userId: string; // identifiant de l’utilisateur

 constructor(options: {
  id?: string,
  dueDate?: number,
  notes?: string,
  tasks?: Task[],
  userId: string  
 }){
  this.id = options.id || null;
  this.dueDate = options.dueDate || 0;
  this.notes = options.notes || ‘’;
  this.tasks = options.tasks || [new Task()];
  this.userId = options.userId;
 }
}

La première chose que nous faisons ici, c’est de lier l’entité journée de travail avec l’entité tâche. Nous importons donc la classe Task dès la première ligne. Puis nous définissons le type de la propriété tasks à la ligne 7, qui est un tableau d’instances de Task. En effet, nous avons défini une classe pour modéliser les tâches au sein de notre application, et nous pouvons l’utiliser pour typer les propriétés d’autres classes ! Le code est ainsi robuste, car on s’assure qu’une journée de travail contient bien les tâches comme nous les avons définis, et en plus notre code est lisible.

Le deuxième point concerne la liaison entre l’entité journée de travail et l’entité utilisateur. C’est ce que nous faisons à la ligne 8 en déclarant la propriété userId, qui contiendra l’identifiant de l’utilisateur qui doit réaliser cette journée de travail. Le plus important est à la ligne 15, où vous pourrez remarquer qu’il n’y a pas l’opérateur “?” devant la propriété userId passé en paramètre, ni de valeur par défaut pour le paramètre de notre constructeur. Concrètement, cela signifie qu’il est impossible de créer une nouvelle journée de travail dans notre application, sans lui associer un utilisateur :

let workday = new Workday(); // erreur : nous devons associer un utilisateur...
let workday = new Workday({userId : ‘johnDoe’}); // ok, c’est bon !

Il s’agit d’une petite précaution que nous mettons en place, pour garantir la consistance de nos données. On est ainsi certain de ne pas tomber sur une journée de travail orpheline dans notre application, sans savoir à qui elle est destinée. 😲

D’accord, j’ai compris. Mais pourquoi nous avons défini des classes pour nos entités, et non des interfaces ?

Si vous allez faire un tour sur internet, il est courant de trouver des exemples de code qui implémente des interfaces TypeScript pour les entités, plutôt que des classes :

export interface User {
 firstname: string;
 lastname: string;
}

Les classes et les interfaces permettent toutes les deux de mettre en place la vérification de type (type-checking) auprès de TypeScript. Cependant, il existe une différence notable entre les deux.

 Une classe est une sorte de moule, à partir duquel nous pouvons créer des objets partageant les mêmes propriétés et méthodes. Au contraire, une interface permet seulement de décrire un objet, mais ne permet pas de l’instancier.

Dans notre cas, nous souhaitons instancier de nouveaux utilisateurs et journées de travail à partir des données du serveur. Nous utilisons donc des classes plutôt que des interfaces.

D’accord, et pourquoi le champs dueDate est un nombre, et pas une date ?

Ah ! C’était un piège ! Je vous l’ai expliqué au début de ce cours. 😲

Rappelez-vous, dans le Firestore, nous allons sauvegarder nos dates sous forme de timestamp. Si vous ne vous souvenez plus ce qu’est un timestamp, relisez la partie concernant les données, au premier chapitre.

Aussi, sauf erreur de ma part, nous n’avons pas ajouté nos entités dans le SharedModule, même si nous les avons placés dans le dossier shared… c’est un oubli ou c’est volontaire ?

En fait, nos classes d’entités TypeScript ne sont pas des éléments propres à Angular. Il ne s’agit ni de composants, ni de services, etc. Nous importerons donc les classes d’entités à chaque fois que nous aurons besoin de typer un paramètre, ou un retour de fonction. Par contre, nous plaçons quand même nos classes dans le dossier shared, car ce sont tout de même des éléments qui sont partagés dans toute l’application.