📧 Reste informé(e) !

Reçois les derniers articles et conseils EasyAngularKit directement dans ta boîte mail.

S'inscrire gratuitement

~6 min de lecture

Angular 21.2 : le changelog commenté — tout ce qui change pour toi

Angular 21.2 vient de sortir (25 février 2026), et c'est une minor release anormalement dense. Signal Forms qui mûrit à vitesse grand V, le support de TypeScript 6, des @switch enfin exhaustifs, et instanceof dans les templates.

On passe tout en revue, feature par feature, avec du code.

TypeScript 6 : Angular est prêt

Angular 21.2 ajoute officiellement le support de TypeScript 6. Si tu n'as pas encore regardé ce que TS 6 apporte, les changements majeurs incluent de meilleures inférences sur les generics et des améliorations significatives de performance du compilateur.

Concrètement, pour mettre à jour :

ng update @angular/core @angular/cli
npm install typescript@6 --save-dev

Attention : TypeScript < 5.9 n'est plus supporté depuis Angular 21.0. Si tu es encore en TS 5.8, il faudra sauter directement à TS 6.

Arrow functions dans les templates

C'est un changement qu'on attendait depuis longtemps. Tu peux maintenant écrire des arrow functions directement dans les expressions de templates.

Avant (21.1) — tu devais créer une méthode dans le composant :


@Component({
    template: `
    <ul>
      @for (item of activeItems(); track item.id) {
        <li>{{ item.name }}</li>
      }
    </ul>
  `
})
export class ProductListComponent {
    items = signal<Product[]>([]);

    activeItems = computed(() => this.items().filter(i => i.active));
}

Maintenant (21.2) — directement dans le template :


@Component({
    template: `
    <ul>
      @for (item of items().filter(i => i.active); track item.id) {
        <li>{{ item.name }}</li>
      }
    </ul>
  `
})
export class ProductListComponent {
    items = signal<Product[]>([]);
}

Évidemment, ça ne veut pas dire qu'il faut mettre toute ta logique dans le template. Pour un filtre simple ou un .map() rapide, c'est pratique. Pour de la logique métier, un computed() reste la bonne approche.

Exhaustive checks sur @switch — enfin type-safe

C'est probablement la feature la plus impactante de cette release pour la qualité de code au quotidien.

Jusqu'ici, le compilateur ne vérifiait pas si tu avais couvert tous les cas d'un union type dans un @switch. Tu pouvais oublier un cas sans aucun avertissement.

Maintenant, le compilateur te prévient :

type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered';

@Component({
    template: `
    @switch (order().status) {
      @case ('pending') { <app-pending-badge /> }
      @case ('processing') { <app-processing-badge /> }
      @case ('shipped') { <app-shipped-badge /> }
      // ❌ Erreur de compilation : 'delivered' n'est pas couvert
    }
  `
})

En combinaison avec le fall-through de @case introduit en 21.1, ça donne des templates très propres :

@switch (order().status) {
    @case ('pending')
    @case ('processing') {
        <app-in-progress-badge />
    } @case ('shipped')    {
        <app-shipped-badge />
    } @case ('delivered') {
        <app-delivered-badge />
    }
}
// ✅ Tous les cas sont couverts, le compilateur est content

Si ton union type évolue (tu ajoutes 'cancelled'), le compilateur te montrera chaque @switch à mettre à jour. C'est exactement le même comportement qu'un switch exhaustif en TypeScript strict, mais côté template.

instanceof dans les templates

Autre ajout côté compilateur : tu peux maintenant utiliser instanceof dans les expressions de templates.


@Component({
    template: `
    @if (error() instanceof HttpErrorResponse) {
      <app-http-error [status]="error().status" />
    } @else {
      <app-generic-error [message]="error().message" />
    }
  `
})
export class ErrorDisplayComponent {
    error = input.required<Error>();
}

Avant, il fallait créer un helper isHttpError() dans le composant ou utiliser un pipe custom. Plus besoin.

Resource composition via snapshots

Les resource() et httpResource() sont très pratiques pour charger des données, mais les composer entre elles était compliqué. Angular 21.2 introduit un mécanisme de snapshots qui résout ce problème.

L'idée : tu peux capturer l'état complet d'une resource (valeur, statut, erreur) sous forme de snapshot, et l'utiliser comme dépendance d'une autre resource ou dans un computed().


@Component({ /* ... */})
export class UserDashboardComponent {
    private userId = input.required<string>();

    // Resource 1 : charger l'utilisateur
    user = httpResource<User>(() => `/api/users/${this.userId()}`);

    // Resource 2 : charger ses commandes, en se basant sur le snapshot de user
    orders = httpResource<Order[]>(() => {
        const userSnapshot = this.user.snapshot();
        // On attend que user soit chargé avant de lancer la requête
        if (userSnapshot.status !== 'resolved') return undefined;
        return `/api/users/${userSnapshot.value!.id}/orders`;
    });

    // Computed qui combine les deux
    dashboardData = computed(() => ({
        user: this.user.value(),
        orders: this.orders.value(),
        isLoading: this.user.isLoading() || this.orders.isLoading(),
    }));
}

C'est un pattern de chaînage déclaratif : la deuxième resource ne se déclenche que quand la première est résolue. Pas de switchMap, pas de pipe(), tout reste dans le monde des signals.

Signal Forms : la grosse évolution de cette release

Le package @angular/forms reçoit 16 commits dans cette 21.2. Les Signal Forms, introduits expérimentalement en 21.0, deviennent beaucoup plus matures.

Parsing natif des inputs

Les Signal Forms comprennent maintenant nativement les types d'inputs HTML. Un <input type="number"> retourne un number, pas un string.

const loginForm = form({
    age: 0,       // Signal Forms sait que c'est un number
    email: '',    // Et ça c'est un string
});
<!-- Le parsing string → number est automatique -->
<input type="number" [formField]="loginForm.age"/>

Si l'utilisateur entre une valeur invalide (par exemple "abc" dans un champ number), une erreur de parsing est automatiquement générée. Plus besoin de validators custom pour ça.

Tu peux aussi binder null sur un input number (utile pour un champ optionnel).

La directive form

Nouveau dans 21.2 : une directive form qui lie ton formulaire signal directement au <form> HTML natif.


<form [formRoot]="loginForm" (ngSubmit)="onSubmit()">
    <input type="email" [formField]="loginForm.email"/>
    <input type="password" [formField]="loginForm.password"/>

    <button type="submit">Se connecter</button>
</form>

Submit amélioré

La fonction submit() accepte maintenant un objet d'options et un callback onInvalid :

submit(this.loginForm, {
    onInvalid: (field) => {
        // Appelé si le formulaire est invalide
        // `field` donne accès au premier champ en erreur
        field.focus(); // Focus automatique sur le premier champ invalide
    },
    action: (value) => {
        // Appelé seulement si le formulaire est valide
        this.authService.login(value);
    },
});

Les options de submit peuvent aussi être configurées au niveau du formulaire plutôt que sur chaque appel.

SignalFormControl : le pont vers Reactive Forms

Si tu as une grosse codebase en Reactive Forms, tu ne vas pas tout réécrire d'un coup. Angular 21.2 introduit SignalFormControl, un pont entre les deux mondes :

import {SignalFormControl} from '@angular/forms';

// Utilisable dans un FormGroup classique
const form = new FormGroup({
    name: new SignalFormControl(''),  // Compatible Reactive Forms
    email: new SignalFormControl(''),
});

// Mais tu peux aussi lire la valeur comme un signal
const nameValue = form.controls.name.signal(); // Signal<string>

C'est la stratégie de migration progressive que beaucoup attendaient. Tu peux convertir tes contrôles un par un, sans casser le formulaire existant.

Autres améliorations forms

  • Custom controls en host directives : les contrôles personnalisés Signal Forms fonctionnent comme host directives
  • Error summary triée par DOM order : le résumé d'erreurs suit l'ordre visuel du formulaire
  • Focus options : possibilité de passer des FocusOptions aux champs
  • Warning sur les états cachés : avertissement quand tu affiches l'état d'un champ masqué

Compiler & performances

Optimisations de la compilation

Le compilateur élimine maintenant les appels restore/reset view inutiles dans le code généré. C'est transparent pour toi, mais ça réduit la taille du bundle et améliore légèrement les performances runtime.

ChangeDetectionStrategy.Eager

Un nouvel alias pour ChangeDetectionStrategy.Default. C'est un renommage sémantique : Eager décrit mieux le comportement réel (détection proactive de changements) que le vague Default, surtout maintenant que le zoneless est le défaut pour les nouvelles apps.

@Component({
    changeDetection: ChangeDetectionStrategy.Eager, // = Default, mais plus explicite
})

Common & Router

ngTemplateOutlet avec injector outlet

Tu peux maintenant passer un injector spécifique au contexte de l'outlet :


<ng-container *ngTemplateOutlet="myTemplate; injector: customInjector"/>

Utile dans les cas où le template projeté a besoin d'accéder à des providers spécifiques.

Location strategies pour trailing slash

Nouvelles stratégies pour gérer les trailing slashes dans les URLs. Si ton backend fait la distinction entre /api/users et /api/users/, tu peux maintenant le contrôler côté Angular.

Image loader : support height

Les loaders d'images intégrés (Cloudflare, Imgix, etc.) supportent maintenant la hauteur en plus de la largeur. Ça permet de mieux optimiser le chargement des images avec un ratio précis.

Router : canMatch enrichi

Le guard canMatch reçoit maintenant un snapshot partiel de ActivatedRouteSnapshot. Tu as accès aux paramètres et data de la route pour prendre ta décision, sans devoir parser l'URL toi-même.

const routes: Routes = [
    {
        path: 'dashboard/:role',
        canMatch: [(route) => {
            // Accès direct aux params avant même que la route soit activée
            return route.params['role'] === 'admin';
        }],
        component: AdminDashboardComponent,
    }
];

Language Service — DX améliorée

  • Linked editing ranges : quand tu renommes un tag HTML ouvrant, le fermant se met à jour automatiquement. Enfin !
  • Support des inline styles : autocomplétion, hover info, quick info et folding ranges pour les styles directement dans le composant
  • JSON schema pour angularCompilerOptions : autocomplétion dans le tsconfig.json
  • File watching côté client : meilleur support du watch via onDidChangeWatchedFiles

Animations imbriquées

Angular 21.2 ajoute le support des nested animations. Jusqu'ici, animer un élément parent et ses enfants en même temps était un casse-tête de timing.

Ce support simplifie les scénarios où tu as besoin d'une animation de conteneur (fade in) avec des animations d'items à l'intérieur (stagger).

En résumé : ce qu'il faut retenir

Feature Impact Action
TypeScript 6 🟢 Élevé Mettre à jour typescript@6
Exhaustive @switch 🟢 Élevé Rien à faire, c'est automatique
Arrow functions templates 🟡 Moyen Utiliser avec parcimonie
instanceof templates 🟡 Moyen Remplacer les helpers existants
Resource snapshots 🟡 Moyen Adopter pour le chaînage de resources
Signal Forms (parsing, directive, submit) 🟢 Élevé Tester sur les nouveaux formulaires
SignalFormControl 🟢 Élevé Stratégie de migration progressive
ChangeDetectionStrategy.Eager 🔵 Faible Alias cosmétique
Language Service amélioré 🟡 Moyen Mettre à jour l'extension VS Code

Pour mettre à jour :

ng update @angular/core@21.2 @angular/cli@21.2

La 21.2 confirme la direction d'Angular : signals everywhere, templates plus expressifs, et TypeScript toujours à la pointe. Si tu attends la stabilisation des Signal Forms pour les adopter en production, cette release montre qu'on s' en rapproche sérieusement.

📧 Reste informé(e) !

Reçois les derniers articles et conseils EasyAngularKit directement dans ta boîte mail.

S'inscrire gratuitement

EasyAngularKit

Formation complète pour maîtriser Angular et développer des applications web modernes.

Navigation

Contact

Légal

© 2026 Easy Angular Kit. Tous droits réservés.