# 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. - Published: 2026-09-03 - Updated: 2026-09-03 - Author: Anthony Fillion-Maillet - Tags: angular, control-flow, templates, signals - Reading time: 10 min --- 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. > **Migração automática disponível** > > 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`, `@for` e `@switch` sã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 a `ng-template` para branches else - Melhor tree-shaking: blocos de controle de fluxo não utilizados têm impacto zero no bundle A [documentação do Angular](https://angular.dev/guide/templates/control-flow) 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: ```typescript // user-status.component.ts import { Component, input } from '@angular/core'; @Component({ selector: 'app-user-status', template: ` @if (user().role === 'admin') { } @else if (user().role === 'editor') { } @else { } ` }) 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: ```html @if (user().profile?.settings?.theme; as theme) {

Tema atual: {{ theme }}

} ``` 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`: ```typescript // product-list.component.ts 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) { } @empty {

Nenhum produto disponível

} ` }) export class ProductListComponent { products = input.required(); } ``` 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: ```html @for (item of items(); track item.id; let i = $index, isLast = $last) {
  • {{ i + 1 }}. {{ item.name }}
  • } ``` 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 ## @switch: Ramificação condicional type-safe O bloco `@switch` fornece pattern matching exaustivo com comparação de igualdade estrita (`===`): ```typescript // status-badge.component.ts import { Component, input } from '@angular/core'; type OrderStatus = 'pending' | 'processing' | 'shipped' | 'delivered'; @Component({ selector: 'app-status-badge', template: ` @switch (status()) { @case ('pending') { Pendente } @case ('processing') { Processando } @case ('shipped') { Enviado } @case ('delivered') { Entregue } } ` }) export class StatusBadgeComponent { status = input.required(); } ``` 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: ```html @switch (userRole()) { @case ('admin') @case ('superadmin') { } @case ('editor') @case ('reviewer') { } @default { } } ``` ### 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: ```typescript 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](/technologies/angular/interview-questions/angular-signals), permitindo reatividade granular: ```typescript // dashboard.component.ts import { Component, computed, signal } from '@angular/core'; @Component({ selector: 'app-dashboard', template: ` @if (isLoading()) { } @else if (hasError()) { } @else { @for (item of filteredItems(); track item.id) { } @empty {

    Nenhum item corresponde aos seus filtros

    } } ` }) export class DashboardComponent { items = signal([]); 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](/blog/angular/angular-19-zoneless-change-detection-performance), 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: ```typescript // Com *ngIf e async pipe (legado)
    {{ user.name }}
    // Com @if e signals (moderno) @if (user(); as user) {
    {{ user.name }}
    } ``` 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: ```html @switch (status()) { @case ('active') { ... } @case ('inactive') { ... } } @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: ```bash # Migrar projeto inteiro ng generate @angular/core:control-flow # Migrar diretório específico ng generate @angular/core:control-flow --path=src/app/features ``` O 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. ## 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 `track` no `@for` é obrigatória: use identificadores únicos como `item.id` para performance ideal, evite `track item` que causa re-renderizações baseadas em referência - `@if` suporta branches nativos `@else if` e `@else` sem `ng-template`, e a palavra-chave `as` cria alias para valores truthy para reutilização - `@switch` usa igualdade estrita e não tem fallthrough: instruções `@case` consecutivas apontam para o mesmo bloco, e `@default never;` habilita verificação de tipos exaustiva - Os blocos de controle de fluxo se integram com [Signals](/technologies/angular/interview-questions/angular-signals) para reatividade granular: apenas os blocos afetados são re-renderizados quando signals são atualizados - Execute `ng generate @angular/core:control-flow` para migrar automaticamente os templates existentes --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pt/blog/angular/angular-control-flow-syntax-if-for-switch-guide