Angular 22: OnPush como padrão, Signal Forms estáveis e o que fazer antes de rodar ng update
Angular 22 chegou com OnPush como default, Signal Forms e httpResource estáveis. Veja o que muda, o que o ng update faz sozinho e o que você precisa revisar manualmente.
Rodei ng update @angular/core@22 @angular/cli@22 num projeto de médio porte e a primeira coisa que vi depois foi um componente que parou de atualizar a tela. Não quebrou o build. Nenhum erro no console. Só parou de funcionar — o tipo de bug mais chato que existe.
O culpado era o OnPush. E a ironia é que a mudança foi exatamente o que a equipe do Angular prometeu que seria: suave, automática, invisível. Para quem entende o que está acontecendo por baixo, é ótimo. Para quem não entende, é uma tarde de debug sem pista de onde começar.
Angular 22, lançado em 3 de junho de 2026, não é uma release de features novas — é a consolidação de três anos de apostas em signals. Zoneless, Signal Forms, Resource API: tudo que estava em developer preview finalmente chegou a estável. Se você acompanhou esse ciclo de perto, vai reconhecer tudo. Se não acompanhou, vai sentir o impacto agora.
Por que o Angular 22 é diferente das últimas versões
Desde o Angular 16, o framework vem apostando pesado numa direção específica: signals como mecanismo central de reatividade, substituindo gradualmente o Zone.js. Cada versão entregou um pedaço — signals no 16, signals em componentes no 17, Signal Forms em developer preview no 19, zoneless experimental no 18, e assim por diante.
O Angular 22 fecha esse ciclo. Não é que algo novo foi inventado — é que as peças ficaram estáveis ao mesmo tempo. Isso muda o que você pode colocar em produção com confiança.
OnPush virou o padrão — e o que isso significa na prática
Esse é o breaking change mais silencioso da release.
Em qualquer versão anterior, um componente sem changeDetection explícito usava ChangeDetectionStrategy.Default, que verifica o estado da árvore a cada evento, timeout e requisição HTTP. Era ineficiente, mas funcionava mesmo se você não soubesse o que estava acontecendo por baixo.
No Angular 22, o padrão mudou para OnPush. Um componente sem changeDetection explícito agora só atualiza a view quando:
- Um
@Inputmuda de referência - Um evento DOM disparado dentro dele ocorre
- Um signal que ele lê muda de valor
- Você chama
markForCheck()manualmente
Se o seu componente dependia de mutação direta de objetos ou de observables sem o pipe async, a tela para de atualizar — silenciosamente.
O que o ng update faz automaticamente: adiciona ChangeDetectionStrategy.Eager em todos os componentes existentes que não tinham changeDetection declarado, preservando o comportamento anterior.
// Antes (Angular 21)
@Component({
selector: 'app-user-card',
template: `...`
})
export class UserCardComponent { ... }
// Depois do ng update (Angular 22)
@Component({
selector: 'app-user-card',
changeDetection: ChangeDetectionStrategy.Eager, // adicionado automaticamente
template: `...`
})
export class UserCardComponent { ... }
ChangeDetectionStrategy.Eager é o novo nome para o comportamento antigo. O ponto importante: após o update, buscar por Eager no codebase é a forma mais rápida de saber quanto do projeto ainda não foi modernizado para OnPush.
O problema que encontrei no meu caso era um componente gerado por uma ferramenta de scaffolding externa que ficou fora do schematic automático. Se você usa geradores customizados ou templates de terceiros, revise manualmente — o schematic só toca nos arquivos que ele consegue rastrear.
Signal Forms finalmente estáveis
Signal Forms saíram de developer preview e estão prontas para produção no Angular 22. A ideia central é diferente dos Reactive Forms: em vez de um FormGroup que controla os valores, você tem um signal que é a fonte de verdade, e o formulário é derivado dele.
A peça central agora é a diretiva formRoot, que conecta o signal form ao elemento <form> no template:
import { Component, signal } from '@angular/core';
import { form } from '@angular/forms/signals';
import { FormRoot, FormField } from '@angular/forms/signals';
@Component({
selector: 'app-checkout',
imports: [FormRoot, FormField],
template: `
<form [formRoot]="checkoutForm">
<input [formField]="checkoutForm.fields.email" type="email" />
<input [formField]="checkoutForm.fields.name" />
<button type="submit">Finalizar</button>
</form>
`
})
export class CheckoutComponent {
model = signal({ email: '', name: '' });
checkoutForm = form(this.model, schema, {
submission: {
action: async (f) => {
await api.checkout(f.value());
}
}
});
}
O formRoot gerencia o evento de submit automaticamente — sem (ngSubmit). A submission.action é chamada quando o formulário é válido e submetido.
Devo migrar meus Reactive Forms agora? Não necessariamente. Signal Forms e Reactive Forms convivem sem problema no Angular 22. A recomendação do time é migrar aos poucos, começando por formulários novos. Formulários antigos e complexos com validação customizada podem levar tempo — avalie o custo antes de começar.
Resource API e httpResource: chega de subscribe
A Resource API também saiu de developer preview. Junto com ela, httpResource — que é provavelmente o que vai mudar mais o dia a dia de quem faz requisições HTTP em componentes.
A ideia: em vez de injetar HttpClient e gerenciar subscribe/unsubscribe manualmente, você declara um recurso que é automaticamente recarregado quando os signals que ele depende mudam.
import { Component, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
interface User {
id: number;
name: string;
email: string;
}
@Component({
selector: 'app-user-profile',
template: `
@if (user.isLoading()) {
<p>Carregando...</p>
} @else if (user.hasValue()) {
<h2>{{ user.value().name }}</h2>
<p>{{ user.value().email }}</p>
} @else if (user.error()) {
<p>Erro ao carregar usuário.</p>
}
`
})
export class UserProfileComponent {
userId = signal(1);
user = httpResource<User>(() => `/api/users/${this.userId()}`);
}
Quando userId muda, a requisição é refeita automaticamente. Sem switchMap, sem takeUntilDestroyed, sem gerenciar o ciclo de vida manualmente.
httpResource retorna um objeto com isLoading(), hasValue(), value() e error() — todos signals. Você compõe a UI em cima deles diretamente no template.
O HttpClient tradicional não foi removido. Mas para novos componentes com requisições simples que dependem de estado reativo, httpResource é objetivamente menos código e menos superfície para erro.
HTTP Fetch por padrão, Node 22 e TypeScript 6
Três mudanças de ambiente que você precisa verificar antes de atualizar:
HTTP Fetch por padrão. O HttpClient agora usa a Fetch API internamente em vez de XMLHttpRequest. Na maioria dos casos é transparente, mas se você tem interceptors que dependem de comportamentos específicos do XHR — como upload progress via reportProgress — teste antes de ir para produção.
Node.js ≥ 22. Se o seu pipeline de CI ainda roda Node 20, o build vai quebrar. Atualize o Node antes de subir a versão do Angular.
TypeScript ≥ 6. O TypeScript 6 trouxe mudanças na resolução de módulos e na tipagem de generics. A maioria do código compila sem alteração, mas se você tem tipos complexos com condicionais aninhados, pode aparecer erro de compilação que não existia antes. Vale rodar tsc --noEmit localmente antes de abrir PR.
Um ponto relacionado que ainda está fora do Angular mas vai impactar o ecossistema em breve: a Microsoft está portando o compilador TypeScript para Go (tsgo), com speedup prometido de 5x–10x. Não é parte do Angular 22, mas é o motivo pelo qual vale atualizar o ambiente de build agora — o ganho de performance está chegando.
O que o ng update faz (e o que ele não faz)
ng update @angular/core@22 @angular/cli@22
O schematic automático faz:
- Adiciona
ChangeDetectionStrategy.Eagerem componentes sem estratégia declarada - Migra
ComponentFactoryResolver(removido no v22) para a API de criação dinâmica atual - Corrige herança de parâmetros de rota filha, que agora sempre herda por padrão
O que ele não faz:
- Migrar Reactive Forms para Signal Forms
- Remover Zone.js da aplicação
- Atualizar interceptors HTTP para Fetch
- Tocar em componentes gerados por ferramentas de scaffolding externas
Duplicar bindings no template — [value]="x" [value]="y" — agora gera erro de compilação. O Angular 21 ignorava isso silenciosamente. Se você tem algum template com binding duplicado por acidente, o build vai parar.
data-* attributes também pararam de ser tratados como property bindings. [data-id]="item.id" não funciona mais:
<!-- Angular 21: funcionava (errado, mas funcionava) -->
<div [data-id]="item.id">
<!-- Angular 22: forma correta -->
<div [attr.data-id]="item.id">
Antes de rodar o update, vale fazer um grep rápido:
grep -rn "\[data-" src/
Se aparecer alguma coisa, corrija antes. O build vai parar mesmo.
Angular 22 vale atualizar agora?
Se o projeto está em produção com pouca cobertura de testes de componente, espere uma semana — deixe a comunidade reportar os edge cases que o schematic não cobre. Se você tem uma suíte de testes razoável e um ambiente de staging, atualize. O schematic é sólido, as mudanças são previsíveis, e ficar no Angular 21 com Node 20 em 2026 começa a ter custo real.
O que fazer antes de rodar o update:
grep -rn "\[data-" src/— corrigir antes- Verificar a versão do Node no CI (precisa ser ≥ 22)
- Revisar componentes criados por geradores customizados
- Rodar
tsc --noEmitpara antecipar erros de TypeScript 6
Angular 22 não é uma versão revolucionária — é uma versão honesta. Fez o que prometeu, entregou estável o que estava em preview, e mudou os defaults para refletir o que a comunidade já considerava boa prática há anos. O custo de migração é real mas gerenciável. O custo de ignorar por mais tempo vai crescer.