~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
FocusOptionsaux 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 letsconfig.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.