Angular 22 : Signal Forms stable, injectAsync(), OnPush par défaut, hydration incrémentale automatique et suppressions legacy. Guide complet et migration v21 → v22.
Angular 22 : vue d'ensemble et calendrier
Angular 22 marque une nouvelle étape dans la transformation du framework : après des années à poser les bases des Signals, du zoneless et des composants standalone, cette version stabilise et consolide ce qui était encore expérimental. La RC.0 est sortie le 13 mai 2026, avec une version stable prévue pour la semaine du 1er juin 2026.
Le message central d'Angular 22 est clair : moins de boilerplate, plus de performances par défaut. L'équipe Angular ne se contente plus d'offrir des APIs réactives en opt-in — elle les impose comme standard pour les nouveaux projets, forçant une transition vers les meilleures pratiques dès la création.
Les 5 axes majeurs d'Angular 22
- Signal Forms stable : les formulaires réactifs basés sur les Signals passent en API publique officielle
- Injection modernisée :
injectAsync()et le décorateur@Servicesimplifient drastiquement la DI - OnPush par défaut : la détection de changements performante devient le comportement standard des nouveaux composants
- Hydration incrémentale automatique : le SSR devient encore plus performant sans configuration
- Nettoyage des APIs legacy : suppression définitive de
ComponentFactoryResolver,NgModuleRef, Hammer.js
| Fonctionnalité | Angular 21 | Angular 22 |
|---|---|---|
| Signal Forms | Developer Preview | API publique stable ✅ |
injectAsync() |
Non disponible | Nouvelle API ✅ |
| ChangeDetection par défaut | Default (Zone.js) |
OnPush pour nouveaux composants ✅ |
| Hydration incrémentale | Opt-in | Activée par défaut ✅ |
ComponentFactoryResolver |
Déprécié | Supprimé ❌ |
| TypeScript minimum | 5.7+ | 5.9+ ✅ |
Entrons dans le détail de chaque nouveauté, en commençant par la plus attendue : les Signal Forms stables.
Signal Forms : API publique stable
Les Signal Forms sont la fonctionnalité la plus attendue d'Angular 22. Après plusieurs mois en Developer Preview, elles passent en API publique stable dans Angular 22.0.0-next.11. C'est la refonte complète du système de formulaires d'Angular, entièrement basée sur les Signals.
Pourquoi Signal Forms révolutionne les formulaires Angular
Les ReactiveFormsModule et FormsModule existants reposent sur Observable et des patterns complexes à maintenir. Signal Forms apporte une API déclarative, synchrone et facilement testable — sans subscribe(), sans valueChanges, sans gestion manuelle de la mémoire.
// AVANT (Reactive Forms classique) — boilerplate important
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({ standalone: true, imports: [ReactiveFormsModule], ... })
export class LoginClassicComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(8)]],
});
}
// Accès à la valeur → this.form.get('email')?.value
// Vérifier la validité → this.form.valid
// Erreur → this.form.get('email')?.hasError('required')
submit() {
if (this.form.valid) {
console.log(this.form.value);
}
}
}
// APRÈS (Signal Forms Angular 22) — API signal-native
import { signalForm, field, required, email, minLength } from '@angular/forms/signal';
@Component({ standalone: true, imports: [SignalFormsModule], ... })
export class LoginSignalComponent {
// Déclaration du formulaire avec schema de validation
form = signalForm({
email: field('', [required(), email()]),
password: field('', [required(), minLength(8)]),
});
// Accès direct via Signal (lecture synchrone)
// this.form.fields.email.value() → valeur actuelle
// this.form.fields.email.valid() → booléen de validité
// this.form.fields.email.errors() → liste des erreurs
submit() {
if (this.form.valid()) {
// getValue() retourne l'objet typé complet
console.log(this.form.getValue());
}
}
}
Validation déclarative et FieldState
Angular 22 introduit FieldState avec la méthode getError() pour accéder aux erreurs de manière typée et sans string magic.
// Signal Forms : validation et accès aux erreurs typé
import { signalForm, field, required, email, minLength } from '@angular/forms/signal';
export class RegisterComponent {
form = signalForm({
username: field('', [required(), minLength(3)]),
email: field('', [required(), email()]),
password: field('', [required(), minLength(8)]),
});
// Récupérer une erreur spécifique par clé (typé, pas de string magic)
get usernameError(): string | null {
const errors = this.form.fields.username.errors();
if (!errors) return null;
if (errors.required) return 'Le nom d\'utilisateur est requis';
if (errors.minlength) return `Minimum ${errors.minlength.requiredLength} caractères`;
return null;
}
// Option debounce — retarder la validation (nouvel en Angular 22)
formWithDebounce = signalForm({
search: field('', [required()], { debounce: 300 }),
});
}
Interopérabilité CVA avec Signal Forms
Angular 22 améliore l'interopérabilité entre Signal Forms et les Control Value Accessors (CVA) existants, permettant d'utiliser vos composants de formulaires personnalisés sans réécriture.
// Composant custom compatible Signal Forms et Reactive Forms
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: 'app-custom-input',
template: `<input [value]="value" (input)="onChange($event.target.value)" />`,
providers: [{
provide: NG_VALUE_ACCESSOR,
useExisting: CustomInputComponent,
multi: true,
}],
})
export class CustomInputComponent implements ControlValueAccessor {
value = '';
onChange = (_: string) => {};
onTouched = () => {};
writeValue(val: string) { this.value = val; }
registerOnChange(fn: (v: string) => void) { this.onChange = fn; }
registerOnTouched(fn: () => void) { this.onTouched = fn; }
}
// Ce CVA fonctionne tel quel dans un signalForm() Angular 22
injectAsync() et injection moderne
Angular 22 introduit injectAsync(), une nouvelle fonction permettant d'injecter des dépendances de manière asynchrone dans un contexte d'injection Angular. C'est la réponse à un manque longtemps ressenti : les services qui s'initialisent de façon asynchrone (chargement de config, feature flags, connexion à une API).
injectAsync() : le cas d'usage
Classiquement, les services nécessitant une initialisation async obligeaient à utiliser des APP_INITIALIZER ou des workarounds complexes. injectAsync() simplifie ce pattern :
// Angular 22 — injectAsync() : injection asynchrone
import { injectAsync, Injectable, Component } from '@angular/core';
// Service avec initialisation asynchrone
@Injectable({ providedIn: 'root' })
export class FeatureFlagService {
private flags: Record<string, boolean> = {};
// Initialisation async : charge les flags depuis une API
async init(): Promise<void> {
const response = await fetch('/api/feature-flags');
this.flags = await response.json();
}
isEnabled(flag: string): boolean {
return this.flags[flag] ?? false;
}
}
// Dans un composant ou un service — injectAsync attend la promesse
@Component({ standalone: true, ... })
export class FeatureComponent {
// injectAsync() : injecte le service ET attend son init()
// Le composant ne se monte qu'après la résolution
readonly featureFlags = injectAsync(async () => {
const svc = inject(FeatureFlagService);
await svc.init();
return svc;
});
}
injectAsync() avec ordonnancement des requêtes
Angular 22 (next.10) introduit également un ordonnancement des métadonnées de requêtes pour garantir un ordre déterministe lors de l'injection de dépendances asynchrones multiples.
// Injection asynchrone avec ordonnancement garanti
import { injectAsync, inject } from '@angular/core';
export class DashboardComponent {
// Les deux injectAsync() s'exécutent en parallèle
// mais Angular garantit l'ordre de résolution
readonly userProfile = injectAsync(async () => {
const svc = inject(UserProfileService);
return svc.loadCurrentUser();
});
readonly permissions = injectAsync(async () => {
const svc = inject(PermissionsService);
return svc.loadForCurrentUser();
});
}
Le décorateur @Service : DI simplifiée
Introduit en Angular 22 (next.9), @Service est une alternative plus concise à @Injectable({ providedIn: 'root' }) pour les services de portée globale — le cas d'usage le plus courant.
// Angular 22 — @Service vs @Injectable comparaison
// ❌ AVANT (verbeux mais toujours valide)
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class UserService {
getUsers() { return fetch('/api/users'); }
}
// ✅ APRÈS (Angular 22 — @Service, plus concis)
import { Service } from '@angular/core';
@Service() // Équivalent exact à @Injectable({ providedIn: 'root' })
export class UserService {
getUsers() { return fetch('/api/users'); }
}
// @Service avec factory sur classe abstraite (nouveau en Angular 22)
abstract class DataSource {
abstract load(): Promise<unknown[]>;
}
@Service({ useFactory: () => new HttpDataSource() })
class DataProvider extends DataSource {
load() { return fetch('/api/data').then(r => r.json()); }
}
@Service ne remplace pas @Injectable — les deux coexistent. Utilisez @Service pour les services globaux simples, et gardez @Injectable pour les cas nécessitant un scope particulier (composant, module, route).
OnPush par défaut : performance native
L'une des décisions architecturales les plus significatives d'Angular 22 : la stratégie de détection de changements ChangeDetectionStrategy.OnPush devient la valeur par défaut pour les nouveaux composants. Concrètement, tout composant généré via ng generate component utilisera désormais OnPush automatiquement.
Pourquoi ce choix ?
L'équipe Angular considère OnPush comme la meilleure pratique depuis des années, mais elle restait opt-in. Les benchmarks montrent que OnPush réduit significativement le nombre de cycles de détection, surtout dans les grandes applications avec des arbres de composants profonds.
// Ce que génère `ng generate component dashboard` dans Angular 22
import { Component, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'app-dashboard',
standalone: true,
imports: [],
templateUrl: './dashboard.component.html',
// OnPush est maintenant le défaut — plus besoin de l'ajouter manuellement
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DashboardComponent {}
Comportement OnPush : rappel essentiel
Avec OnPush, Angular ne vérifie le composant que dans quatre cas précis :
- Un input a changé de référence (objet ou tableau remplacé, pas muté)
- Un événement DOM a été déclenché dans le composant (click, input, etc.)
- Un Observable souscrit avec
async pipea émis une nouvelle valeur - Un Signal utilisé dans le template a changé de valeur
// OnPush avec Signals — le duo parfait Angular 22
import { Component, ChangeDetectionStrategy, signal, computed } from '@angular/core';
@Component({
selector: 'app-cart',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<!-- Les Signals déclenchent automatiquement la mise à jour -->
<p>Articles : {{ itemCount() }}</p>
<p>Total : {{ total() | currency:'EUR' }}</p>
<button (click)="addItem()">Ajouter</button>
`,
})
export class CartComponent {
// Signals = source de vérité réactive
private items = signal<{ price: number }[]>([]);
// computed() se recalcule automatiquement quand items() change
itemCount = computed(() => this.items().length);
total = computed(() => this.items().reduce((sum, i) => sum + i.price, 0));
addItem() {
// signal.update() → Angular détecte le changement même en OnPush
this.items.update(list => [...list, { price: 9.99 }]);
}
}
Cas où OnPush peut surprendre
Si vous mutez un objet au lieu de le remplacer, OnPush ne détectera pas le changement. C'est intentionnel — et c'est ce qui le rend performant.
// ⚠️ Piège classique avec OnPush — mutation vs remplacement
export class ListComponent {
items = signal<string[]>([]);
// ❌ FAUX — mutation directe : Angular ne détecte pas le changement
addItemWrong(name: string) {
const list = this.items();
list.push(name); // mutation de l'array existant
// Angular ne voit pas de changement de référence → pas de rendu
}
// ✅ CORRECT — remplacement de référence : signal.update() crée un nouveau tableau
addItemCorrect(name: string) {
this.items.update(list => [...list, name]);
// Nouveau tableau → Angular détecte le changement → rendu déclenché
}
}
- Remplacer les mutations d'objets/tableaux par du remplacement de référence
- Utiliser
async pipeou Signals pour les données asynchrones - Injecter
ChangeDetectorRef.markForCheck()si vous avez des changements en dehors du contexte Angular - Tester chaque composant après activation d'OnPush
Hydration incrémentale par défaut
Angular 22 (next.8) active l'hydration incrémentale par défaut pour les applications SSR. Plus besoin de la configurer manuellement — elle s'active dès que vous utilisez Angular SSR, offrant des gains de performance immédiats sur le Time to Interactive (TTI).
Qu'est-ce que l'hydration incrémentale ?
L'hydration incrémentale permet à Angular d'hydrater les composants progressivement, au lieu de tout hydrater d'un coup au chargement. Les composants hors viewport ou non critiques sont hydratés seulement quand ils deviennent nécessaires.
// Angular 21 — hydration incrémentale : configuration manuelle requise
// app.config.ts
import { provideClientHydration, withIncrementalHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(
withIncrementalHydration() // Opt-in explicite requis
),
],
};
// Angular 22 — hydration incrémentale : activée automatiquement
// app.config.ts — plus besoin de withIncrementalHydration() !
import { provideClientHydration } from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(), // L'hydration incrémentale est incluse par défaut
],
};
Contrôle granulaire avec @defer
L'hydration incrémentale s'intègre naturellement avec @defer pour hydrater les blocs de contenu de façon conditionnelle :
// Template Angular 22 — @defer + hydration incrémentale
// La section commentaires n'est hydratée qu'à la demande
<!-- Contenu principal : hydraté en priorité -->
<article>
<h1>{{ article.title }}</h1>
<p>{{ article.content }}</p>
</article>
<!-- Commentaires : hydratés seulement quand l'utilisateur scrolle jusqu'ici -->
@defer (on viewport; hydrate on interaction) {
<app-comments [articleId]="article.id" />
} @placeholder {
<div class="comments-placeholder">Chargement des commentaires...</div>
}
SSR : caching des ressources
Angular 22 améliore également le caching des ressources SSR. Les données chargées côté serveur sont sérialisées et transférées au client, évitant les double-fetch au moment de l'hydration.
// Angular 22 — resource() avec caching SSR automatique
import { resource, inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Component({ standalone: true, ... })
export class ArticleComponent {
private http = inject(HttpClient);
// resource() avec SSR : les données sont cachées et transférées au client
// Plus de double requête HTTP lors de l'hydration
article = resource({
loader: () => this.http.get<Article>('/api/articles/1').toPromise(),
// Angular 22 : transfert automatique de l'état SSR → client
});
}
HTTP et Router : nouvelles options
Angular 22 apporte plusieurs améliorations ciblées au module HTTP et au Router, sans révolutions majeures mais avec des gains concrets pour les cas d'usage courants.
HTTP : reportUploadProgress et reportDownloadProgress
L'option reportProgress est dépréciée au profit de deux options distinctes et plus précises : reportUploadProgress et reportDownloadProgress.
// Angular 22 — suivi séparé upload et download
import { HttpClient, HttpEventType } from '@angular/common/http';
@Injectable({ providedIn: 'root' })
export class FileUploadService {
constructor(private http: HttpClient) {}
// ❌ DÉPRÉCIÉ en Angular 22 — reportProgress générique
uploadOld(file: File) {
return this.http.post('/api/upload', file, {
reportProgress: true, // Déprécié
observe: 'events',
});
}
// ✅ NOUVEAU — options distinctes plus expressives
uploadNew(file: File) {
return this.http.post('/api/upload', file, {
reportUploadProgress: true, // Suivi progression upload
reportDownloadProgress: false, // Pas besoin pour un upload simple
observe: 'events',
}).pipe(
filter(e => e.type === HttpEventType.UploadProgress),
map(e => Math.round(100 * e.loaded / (e.total ?? e.loaded))),
);
}
// Téléchargement avec suivi progress
downloadFile(url: string) {
return this.http.get(url, {
responseType: 'blob',
reportDownloadProgress: true, // Suivi de la progression du download
observe: 'events',
});
}
}
allowedHosts pour renderModule (SSR)
Angular 22 ajoute une option allowedHosts à renderModule pour renforcer la sécurité côté serveur en limitant les hôtes autorisés à déclencher le rendu SSR :
// Angular 22 — renderModule avec allowedHosts (sécurité SSR)
import { renderModule } from '@angular/platform-server';
import { AppModule } from './app/app.module';
// Sécuriser le rendu SSR : seuls ces hôtes peuvent déclencher le rendu
const html = await renderModule(AppModule, {
document: '<!doctype html><html><body><app-root></app-root></body></html>',
url: 'https://monsite.com/',
// Nouveau en Angular 22 : protection contre les host-injection attacks
allowedHosts: ['monsite.com', 'www.monsite.com'],
});
Router : paramsInheritanceStrategy par défaut
Angular 22 change la valeur par défaut de paramsInheritanceStrategy à 'always'. Cela signifie que les paramètres de route des parents sont maintenant hérités par les routes enfants sans configuration supplémentaire.
// Angular 22 — paramsInheritanceStrategy = 'always' par défaut
// Routes imbriquées — exemple
const routes: Routes = [{
path: 'products/:categoryId',
component: CategoryComponent,
children: [{
path: ':productId',
component: ProductComponent,
// ProductComponent peut maintenant accéder à categoryId
// SANS configurer paramsInheritanceStrategy dans le router
}],
}];
// Dans ProductComponent
@Component({ standalone: true, ... })
export class ProductComponent {
private route = inject(ActivatedRoute);
// ✅ Angular 22 : categoryId hérité automatiquement du parent
categoryId = this.route.snapshot.params['categoryId'];
productId = this.route.snapshot.params['productId'];
}
Language Service : inlay hints pour les templates
Le language service Angular 22 (VS Code extension) supporte maintenant les inlay hints dans les templates — des suggestions de types affichées directement dans le code, similaires à ce que TypeScript offre dans les fichiers .ts.
@for (item of items; track item.id), le language service peut afficher le type inféré de item directement dans l'éditeur, sans avoir à chercher la définition de items.
Breaking changes et suppressions
Angular 22 procède à un nettoyage significatif d'APIs dépréciées depuis plusieurs versions. Ces suppressions sont les breaking changes les plus importants à anticiper avant la migration.
Suppressions majeures
| API supprimée | Remplacée par | Depuis quelle version dépréciée |
|---|---|---|
ComponentFactoryResolver |
ViewContainerRef.createComponent() |
Angular 13 |
createNgModuleRef() |
createEnvironmentInjector() |
Angular 14 |
| Intégration Hammer.js | Listeners natifs ou librairie tierce | Angular 19 |
checkNoChanges() |
TestBed.flushEffects() en tests |
Angular 20 |
reportProgress (HttpClient) |
reportUploadProgress / reportDownloadProgress |
Angular 22 |
ComponentFactoryResolver : migration
// ❌ SUPPRIMÉ en Angular 22 — ComponentFactoryResolver
import { ComponentFactoryResolver, ViewContainerRef } from '@angular/core';
@Component({ ... })
export class OldDynamicComponent {
constructor(
private cfr: ComponentFactoryResolver, // ❌ N'existe plus en Angular 22
private vcr: ViewContainerRef,
) {}
create() {
const factory = this.cfr.resolveComponentFactory(MyComponent); // ❌
this.vcr.createComponent(factory); // ❌
}
}
// ✅ CORRECT — Angular 13+ et Angular 22
import { ViewContainerRef } from '@angular/core';
@Component({ standalone: true, ... })
export class NewDynamicComponent {
private vcr = inject(ViewContainerRef);
create() {
// Directement sur ViewContainerRef — plus de factory nécessaire
const ref = this.vcr.createComponent(MyComponent);
ref.setInput('title', 'Mon composant dynamique');
}
}
Hammer.js : migration vers Pointer Events
// ❌ SUPPRIMÉ en Angular 22 — intégration Hammer.js
// angular.json — l'option HammerModule n'est plus disponible
// ✅ ALTERNATIVE — Pointer Events natifs ou HammerJS standalone
// Option 1 : Pointer Events natifs (recommandée)
@Component({
template: `<div (pointerdown)="onPress($event)">Press me</div>`,
})
export class GestureComponent {
onPress(event: PointerEvent) {
console.log('Pressed at:', event.clientX, event.clientY);
}
}
// Option 2 : utiliser HammerJS directement (sans intégration Angular)
import Hammer from 'hammerjs';
@Component({ ... })
export class HammerComponent implements AfterViewInit {
@ViewChild('target') target!: ElementRef;
ngAfterViewInit() {
const mc = new Hammer(this.target.nativeElement);
mc.on('swipeleft', () => this.onSwipeLeft());
}
onSwipeLeft() { console.log('Swiped left!'); }
}
Changements TypeScript
- TypeScript 5.9 minimum — vérifier que votre tsconfig.json est compatible
- Validation min/max stricte : les validateurs
min()etmax()n'acceptent plus les strings — utiliser des numbers directement - Template : safe navigation réduit les nullables —
user?.nameest maintenant correctement inféré commestring | undefined(passtring | null | undefined) - Sélecteurs dupliqués : le diagnostic NG8023 génère maintenant une erreur (pas un warning) si deux composants ont le même sélecteur
Migrer de v21 à v22 : guide pas à pas
La migration d'Angular 21 vers Angular 22 est globalement fluide grâce aux schematics automatiques, mais les breaking changes listés ci-dessus nécessitent une attention particulière. Voici le processus recommandé.
Étape 1 : vérifier les prérequis
# Vérifier la version de Node.js (20.x ou 22.x recommandé pour Angular 22)
node --version
# Vérifier la version de npm
npm --version
# Angular 22 requiert TypeScript 5.9+
# Vérifier la version actuelle
npx tsc --version
Étape 2 : lancer ng update
# Mettre à jour Angular CLI en premier
npm install -g @angular/cli@22
# Dans votre projet : mettre à jour Angular core et CLI
ng update @angular/core@22 @angular/cli@22
# Si vous utilisez Angular Material
ng update @angular/material@22
# Si vous utilisez NgRx
ng update @ngrx/store@17 # NgRx v17 compatible Angular 22
Étape 3 : gérer les schematics automatiques
ng update lance automatiquement les schematics de migration. Vérifiez chaque fichier modifié :
# Après ng update, vérifier les changements dans le projet
git diff --stat
# Les schematics automatiques couvrent :
# - Suppression des imports ComponentFactoryResolver
# - Migration createNgModuleRef → createEnvironmentInjector
# - Ajout automatique de changeDetection: OnPush sur les nouveaux composants
# - Mise à jour des validateurs min/max (string → number)
Étape 4 : vérifier les breaking changes manuels
# Rechercher les usages de ComponentFactoryResolver restants
grep -r "ComponentFactoryResolver" src/ --include="*.ts"
# Rechercher les usages de createNgModuleRef
grep -r "createNgModuleRef" src/ --include="*.ts"
# Vérifier les imports HammerModule
grep -r "HammerModule" src/ --include="*.ts"
# Vérifier les usages de checkNoChanges()
grep -r "checkNoChanges" src/ --include="*.ts"
Étape 5 : tester et valider
# Lancer les tests unitaires
ng test
# Vérifier les types TypeScript
ng build --configuration=development
# Lancer les tests e2e (Playwright ou Cypress)
npx playwright test
# Build de production
ng build --configuration=production
- Node.js 20.x ou 22.x installé
- TypeScript 5.9+ dans
tsconfig.json ng update @angular/core@22 @angular/cli@22exécutéComponentFactoryResolverremplacé parViewContainerRef.createComponent()HammerModulesupprimé, listeners natifs ou HammerJS standalone à la place- Validateurs
min()/max()passent des numbers (pas des strings) - Tests unitaires passants
- Build production sans erreurs TypeScript
- Tests e2e validés
Conclusion et perspectives
Angular 22 est une version de consolidation et de maturité. Elle ne réinvente pas le framework — elle finalise la transformation engagée depuis Angular 17. Les Signals, le zoneless, les composants standalone : tout est maintenant stable, performant et surtout activé par défaut.
Les points les plus impactants pour vos projets :
- Signal Forms stable : si vous faites des formulaires complexes, c'est le moment de migrer
- OnPush par défaut : vos nouveaux composants seront plus performants sans effort
- Hydration incrémentale automatique : les apps SSR gagnent en TTI sans configuration
- Breaking changes : anticipez la suppression de
ComponentFactoryResolversi vous créez des composants dynamiques
resource() streams synchrones, l'amélioration du profiling, et potentiellement la sortie officielle d'Angular Signals hors de @angular/core pour une réutilisation dans d'autres contextes.
Pour aller plus loin, explorez nos articles connexes sur Angular 21, les Signal Forms en détail, l'injection inject() et les meilleures pratiques performance Angular. La v22 est disponible en RC depuis le 13 mai 2026 — vous pouvez déjà la tester sur vos projets non critiques.