# 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