Sintaxe de controle de fluxo no Angular 2026: @if, @for, @switch e perguntas de entrevista
Guia completo sobre a sintaxe de controle de fluxo do Angular com @if, @for e @switch. Aprenda a substituir as diretivas estruturais por blocos de controle modernos e prepare-se para entrevistas técnicas.

A sintaxe de controle de fluxo do Angular (@if, @for, @switch) substitui as diretivas estruturais *ngIf, *ngFor e *ngSwitch que dominaram os templates do Angular por anos. Introduzida no Angular 17, estabilizada desde o Angular 18 e tornando-se a sintaxe padrão no Angular 22, esta abordagem baseada em blocos aproxima os templates das construções de programação padrão enquanto permite melhores otimizações de performance.
Execute ng generate @angular/core:control-flow para migrar automaticamente os templates existentes das diretivas estruturais para a nova sintaxe de controle de fluxo. Ambas as sintaxes coexistem durante a migração, mas ngIf, ngFor e ngSwitch estão soft-deprecated desde o Angular 19.
Por que o Angular substituiu as diretivas estruturais pela sintaxe de blocos
As diretivas estruturais exigiam importar CommonModule, usavam uma microsintaxe diferente do JavaScript e forçavam os desenvolvedores a envolver o conteúdo em ng-template para condições complexas. A nova sintaxe de controle de fluxo resolve esses problemas:
- Sem imports necessários:
@if,@fore@switchsão integrados ao framework - Sintaxe similar ao JavaScript: condições e loops se leem como código padrão
- Suporte nativo a
@else: não é mais necessário referências ang-templatepara branches else - Melhor tree-shaking: blocos de controle de fluxo não utilizados têm impacto zero no bundle
A documentação do Angular recomenda adotar completamente a sintaxe de blocos em todos os novos projetos e migrar progressivamente as bases de código existentes.
@if: Renderização condicional sem ng-template
O bloco @if renderiza conteúdo condicionalmente baseado em uma expressão truthy. Diferente do *ngIf, ele suporta branches @else if e @else diretamente:
import { Component, input } from '@angular/core';
@Component({
selector: 'app-user-status',
template: `
@if (user().role === 'admin') {
<app-admin-panel />
} @else if (user().role === 'editor') {
<app-editor-panel />
} @else {
<app-viewer-panel />
}
`
})
export class UserStatusComponent {
user = input.required<{ role: string }>();
}O bloco @if também suporta aliasing de variáveis com a palavra-chave as, que extrai valores de expressões aninhadas:
<!-- Evita acessos repetidos a propriedades -->
@if (user().profile?.settings?.theme; as theme) {
<p>Tema atual: {{ theme }}</p>
}Esse padrão é particularmente útil ao trabalhar com dados assíncronos ou objetos profundamente aninhados, já que a variável com alias só é definida quando a condição é truthy.
@for: Iteração com expressão track obrigatória
O bloco @for itera sobre qualquer iterável JavaScript, com otimizações para arrays. Diferente do *ngFor, ele exige uma expressão track:
import { Component, input } from '@angular/core';
interface Product {
id: string;
name: string;
price: number;
}
@Component({
selector: 'app-product-list',
template: `
@for (product of products(); track product.id) {
<app-product-card [product]="product" />
} @empty {
<p>Nenhum produto disponível</p>
}
`
})
export class ProductListComponent {
products = input.required<Product[]>();
}A expressão track informa ao Angular como identificar cada item entre re-renderizações. Escolher a propriedade de tracking correta impacta diretamente a performance:
| Expressão Track | Caso de uso | Impacto na performance |
|---|---|---|
track item.id | Itens com identificadores únicos | Ótimo: atualizações DOM mínimas |
track $index | Listas estáticas que nunca reordenam | Aceitável: re-renderização completa ao reordenar |
track item | Tracking por referência | Ruim: nova referência = novo nó DOM |
Variáveis contextuais em blocos @for
O Angular fornece variáveis implícitas dentro dos blocos @for que expõem metadados de iteração:
@for (item of items(); track item.id; let i = $index, isLast = $last) {
<li class="item" [class.last]="isLast">
{{ i + 1 }}. {{ item.name }}
</li>
}Variáveis contextuais disponíveis:
$index: posição base zero$count: número total de itens$first,$last: flags booleanas para o primeiro/último item$even,$odd: flags booleanas baseadas na paridade do índice
Pronto para mandar bem nas entrevistas de Angular?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
@switch: Ramificação condicional type-safe
O bloco @switch fornece pattern matching exaustivo com comparação de igualdade estrita (===):
import { Component, input } from '@angular/core';
type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered';
@Component({
selector: 'app-status-badge',
template: `
@switch (status()) {
@case ('pending') {
<span class="badge badge-gray">Pendente</span>
}
@case ('processing') {
<span class="badge badge-blue">Processando</span>
}
@case ('shipped') {
<span class="badge badge-yellow">Enviado</span>
}
@case ('delivered') {
<span class="badge badge-green">Entregue</span>
}
}
`
})
export class StatusBadgeComponent {
status = input.required<OrderStatus>();
}Diferente do switch do JavaScript, o @switch do Angular não tem comportamento de fallthrough. Múltiplas condições apontando para o mesmo bloco exigem instruções @case consecutivas:
@switch (userRole()) {
@case ('admin')
@case ('superadmin') {
<app-admin-dashboard />
}
@case ('editor')
@case ('reviewer') {
<app-editor-dashboard />
}
@default {
<app-viewer-dashboard />
}
}Verificação de tipos exaustiva com @default never
O Angular 22 suporta verificação de exaustividade em tempo de compilação. Usar @default never; declara que não devem existir casos restantes:
type Theme = 'light' | 'dark' | 'system';
// Erro de compilação se um valor Theme estiver faltando nos blocos @case
@switch (theme()) {
@case ('light') { /* ... */ }
@case ('dark') { /* ... */ }
@case ('system') { /* ... */ }
@default never;
}Adicionar um novo valor à union Theme dispara um erro de compilação, forçando os desenvolvedores a tratar todos os casos.
Integração da sintaxe de controle de fluxo com Angular Signals
Os blocos de controle de fluxo se integram perfeitamente com Angular Signals, permitindo reatividade granular:
import { Component, computed, signal } from '@angular/core';
@Component({
selector: 'app-dashboard',
template: `
@if (isLoading()) {
<app-skeleton />
} @else if (hasError()) {
<app-error [message]="errorMessage()" />
} @else {
@for (item of filteredItems(); track item.id) {
<app-item-card [item]="item" />
} @empty {
<p>Nenhum item corresponde aos seus filtros</p>
}
}
`
})
export class DashboardComponent {
items = signal<Item[]>([]);
filter = signal('');
isLoading = signal(true);
hasError = signal(false);
errorMessage = signal('');
// O signal computed só recalcula quando as dependências mudam
filteredItems = computed(() =>
this.items().filter(item =>
item.name.toLowerCase().includes(this.filter().toLowerCase())
)
);
}Quando um signal é atualizado, o Angular reavalia apenas os blocos de controle de fluxo afetados. Combinado com a detecção de mudanças zoneless do Angular, isso permite renderização altamente otimizada.
Perguntas de entrevista frequentes sobre controle de fluxo do Angular
Entrevistas técnicas frequentemente testam o entendimento da sintaxe de controle de fluxo, especialmente as diferenças em relação às diretivas estruturais.
Pergunta 1: Por que track é obrigatório no @for?
A expressão track fornece ao Angular uma identidade estável para cada item. Sem ela, o Angular não consegue determinar eficientemente quais nós DOM criar, atualizar ou destruir quando a coleção muda. Tornar track obrigatório força os desenvolvedores a tomar uma decisão explícita sobre identidade, evitando as armadilhas de performance do tracking implícito por referência.
Pergunta 2: Como @if difere de *ngIf com async pipe?
Ambos podem lidar com observables, mas @if com signals fornece acesso síncrono aos valores:
// Com *ngIf e async pipe (legado)
<div *ngIf="user$ | async as user">{{ user.name }}</div>
// Com @if e signals (moderno)
@if (user(); as user) {
<div>{{ user.name }}</div>
}A abordagem com signals evita gerenciamento de subscriptions e se integra melhor com a detecção de mudanças do Angular.
Pergunta 3: O @switch pode substituir cadeias complexas de @if/@else if?
O @switch deve ser usado quando se compara uma única expressão com múltiplos valores discretos. Para condições booleanas complexas envolvendo diferentes expressões, @if/@else if continua sendo mais apropriado:
<!-- Usar @switch para uma única expressão, múltiplos valores -->
@switch (status()) {
@case ('active') { ... }
@case ('inactive') { ... }
}
<!-- Usar @if para múltiplas expressões -->
@if (isAdmin() && hasPermission('write')) {
...
} @else if (isEditor()) {
...
}Pergunta 4: O que acontece com @for quando a coleção está vazia?
Quando o iterável não contém itens, o Angular pula completamente o conteúdo do @for. O bloco opcional @empty renderiza conteúdo de fallback neste caso. Sem @empty, nada é renderizado, o que difere de alguns frameworks que renderizam um container vazio.
Migração das diretivas estruturais para controle de fluxo
O CLI do Angular fornece um schematic de migração automatizado:
# Migrar projeto inteiro
ng generate @angular/core:control-flow
# Migrar diretório específico
ng generate @angular/core:control-flow --path=src/app/featuresO schematic lida com a maioria das transformações automaticamente, mas é necessário revisar a saída para casos especiais:
| Diretiva estrutural | Equivalente controle de fluxo |
|---|---|
*ngIf="condition" | @if (condition) { } |
*ngIf="condition; else elseBlock" | @if (condition) { } @else { } |
*ngFor="let item of items" | @for (item of items; track item) { } |
*ngFor="let item of items; index as i" | @for (item of items; track item; let i = $index) { } |
[ngSwitch] + *ngSwitchCase | @switch + @case |
Após a migração, remova os imports de CommonModule dos componentes standalone que não usam mais diretivas estruturais.
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Pontos-chave sobre a sintaxe de controle de fluxo do Angular
- A sintaxe de controle de fluxo do Angular (
@if,@for,@switch) é a abordagem recomendada desde o Angular 19, substituindo as diretivas estruturais - A expressão
trackno@foré obrigatória: use identificadores únicos comoitem.idpara performance ideal, evitetrack itemque causa re-renderizações baseadas em referência @ifsuporta branches nativos@else ife@elsesemng-template, e a palavra-chaveascria alias para valores truthy para reutilização@switchusa igualdade estrita e não tem fallthrough: instruções@caseconsecutivas apontam para o mesmo bloco, e@default never;habilita verificação de tipos exaustiva- Os blocos de controle de fluxo se integram com Signals para reatividade granular: apenas os blocos afetados são re-renderizados quando signals são atualizados
- Execute
ng generate @angular/core:control-flowpara migrar automaticamente os templates existentes
Você saberia encontrar o bug em Angular?
Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Escrito por
Anthony Fillion-MailletFundador da SharpSkill
Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.
Atualizado em 3 de setembro de 2026
Tags
Compartilhar
Artigos relacionados

Angular Signals e Computed em 2026: Reatividade Granular e Perguntas de Entrevista
Dominar Signals do Angular, computed, effect e linkedSignal no Angular 20+. Padrões de reatividade fina e preparação para entrevistas técnicas.

Perguntas de entrevista Angular 19: Signals, SSR e conceitos essenciais
As perguntas de entrevista Angular 19 mais comuns: Signals, hidratação incremental, detecção de mudanças sem Zone.js e novas APIs reativas com exemplos de código e respostas esperadas.

RxJS no Angular 2026: operators, Subjects e interop com Signals
RxJS no Angular 2026: domine os operators, os Subjects e os padrões de interop com Signals usados em produção, além das perguntas de entrevista mais frequentes.