RxJS Operators : map, filter, switchMap & merge

🏷️ Front-end 📅 03/04/2026 20:00:00 👤 Mezgani Said
Rxjs Operators Angular Observable
RxJS Operators : map, filter, switchMap & merge

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.

Mental model : Pensez aux Observables comme des tapis roulants. Les operators sont les machines qui les trient, les transforment et les dévient. Le 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;
});
Quand utiliser map() :
  • ✅ 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
});
Points clés :
  • ✅ Retourne true pour laisser passer, false pour 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 vs mergeMap :
  • 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);
});
Concurrency control : Vous pouvez limiter le nombre de requêtes parallèles :
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ées
  • filter() → garder ou jeter les valeurs
  • switchMap() → basculer entre Observables (cherche, filtres, routes)
  • mergeMap() → exécuter en parallèle (uploads, événements)
À retenir : En doute entre switchMap et mergeMap ? Demandez-vous : "Si l'utilisateur déclenche deux fois, la première requête doit-elle être annulée ?" Oui → switchMap. Non → mergeMap.