Guide complet des operators RxJS les plus utilisés : map, filter, switchMap, mergeMap, flatMap. Exemples concrets et différences de comportement.
Introduction
RxJS Operators sont le cœur de la programmation réactive. Ce sont des fonctions qui transforment, filtrent, combinent ou contrôlent vos Observables. Voici les 4 operators essentiels qui couvrent 80% de vos besoins en production.
pipe() assemble ces machines.
map() — Transformer chaque valeur
map() transforme CHAQUE valeur émise par l'Observable en appliquant une fonction :
import { map } from 'rxjs/operators';
// Exemple 1 : Transformer des utilisateurs bruts en DTO enrichi
this.userService.getUsers().pipe(
map(users => users.map(u => ({
...u,
fullName: `${u.firstName} ${u.lastName}`, // Créer fullName
initials: u.firstName[0] + u.lastName[0] // Ajouter des initiales
})))
).subscribe(enrichedUsers => {
this.users = enrichedUsers;
});
// Exemple 2 : Extraire une propriété spécifique
this.userService.getUser(id).pipe(
map(user => user.email) // Retourner juste l'email
).subscribe(email => {
this.userEmail = email;
});
- ✅ Transformer une structure API en modèle métier
- ✅ Calculer des valeurs dérivées (fullName, initials, etc.)
- ✅ Formatter des données pour l'affichage
filter() — Filtrer les valeurs
filter() ne laisse passer que les valeurs qui respectent une condition :
import { filter, map } from 'rxjs/operators';
// Exemple 1 : Filtrer par condition simple
this.userService.getUsers().pipe(
filter(users => users.length > 0), // Ne pas émettre si tableau vide
map(users => users.filter(u => u.age >= 18)) // Garder que les majeurs
).subscribe(adults => {
this.adults = adults;
});
// Exemple 2 : Filtrer en live search (ne chercher que si 3+ caractères)
this.searchInput$.pipe(
map(text => text.trim()),
filter(text => text.length >= 3), // Ignorer les recherches courtes
switchMap(text => this.searchService.search(text))
).subscribe(results => {
this.results = results;
});
// Exemple 3 : Filtrer par type (type guard)
this.items$.pipe(
filter((item): item is Product => item instanceof Product)
).subscribe(products => {
// Ici, TypeScript sait que item est un Product
});
- ✅ Retourne
truepour laisser passer,falsepour bloquer - ✅ Peut éliminer complètement une émission (contrairement à
map()) - ✅ Combiné avec
map(), forme un duo puissant
switchMap() — Basculer et annuler
switchMap() switche vers un nouvel Observable et annule automatiquement les précédents. C'est votre allié pour les recherches en direct :
import { switchMap, debounceTime } from 'rxjs/operators';
// Exemple 1 : Recherche en direct (autocomplet)
this.searchInput$.pipe(
debounceTime(300), // Attendre 300ms avant de chercher
switchMap(query => {
if (!query) return of([]); // Requête vide = aucun résultat
return this.searchService.search(query);
// Si l'utilisateur tape avant la fin de la requête,
// la précédente est ANNULÉE
})
).subscribe(results => {
this.results = results;
});
// Exemple 2 : Charger le détail au changement de route
this.route.params.pipe(
switchMap(params => this.userService.getUser(params.id))
// Si l'utilisateur change de route avant la fin,
// la requête précédente est annulée
).subscribe(user => {
this.user = user;
});
- switchMap : Annule la requête précédente. Idéal pour recherches en direct, filtres, routes
- mergeMap : Exécute tout en parallèle. Idéal pour uploads multiples, événements indépendants
mergeMap() — Exécuter en parallèle
mergeMap() lance plusieurs Observables sans annuler les précédents. Parfait pour les uploads multiples ou événements indépendants :
import { mergeMap, map } from 'rxjs/operators';
// Exemple 1 : Upload de plusieurs fichiers en parallèle
this.fileInput$.pipe(
mergeMap(files => {
return from(Array.from(files)).pipe( // Chaque fichier devient un Observable
mergeMap(file => this.uploadService.upload(file)),
map(result => ({ fileName: result.name, size: result.size }))
);
})
).subscribe(uploadedFile => {
console.log('Fichier uploadé :', uploadedFile);
this.uploadedFiles.push(uploadedFile);
});
// Exemple 2 : Plusieurs clics déclenchent plusieurs actions
this.deleteButton$.pipe(
mergeMap(item => {
// Chaque clic lancera une suppression (pas d'annulation)
return this.deleteService.delete(item.id).pipe(
map(() => `${item.name} supprimé`)
);
})
).subscribe(message => {
this.notify.success(message);
});
mergeMap(file => this.upload(file), 2) // Max 2 uploads simultanés
Conclusion
Ces 4 operators sont votre arsenal au quotidien. Ensemble, ils couvrent la majorité de vos besoins :
map()→ transformer les donnéesfilter()→ garder ou jeter les valeursswitchMap()→ basculer entre Observables (cherche, filtres, routes)mergeMap()→ exécuter en parallèle (uploads, événements)