Синтаксис Control Flow в Angular 2026: @if, @for, @switch та питання на співбесідах
Повний посібник з блокового синтаксису керування потоком в Angular. Вивчіть @if, @for, @switch з практичними прикладами коду та підготуйтесь до технічних співбесід.

Синтаксис control flow в Angular (@if, @for, @switch) замінює структурні директиви *ngIf, *ngFor та *ngSwitch, які роками домінували в шаблонах Angular. Представлений в Angular 17, стабільний з Angular 18 та стандартний з Angular 22, цей блоковий синтаксис наближає шаблони до стандартних програмних конструкцій, одночасно забезпечуючи кращі оптимізації продуктивності.
Запустіть ng generate @angular/core:control-flow для автоматичної міграції існуючих шаблонів зі структурних директив на новий синтаксис control flow. Обидва синтаксиси можуть співіснувати під час міграції, але ngIf, ngFor та ngSwitch м'яко застарілі з Angular 19.
Чому Angular замінив структурні директиви блоковим синтаксисом
Структурні директиви вимагали імпорту CommonModule, використовували мікро-синтаксис, що відрізнявся від JavaScript, і змушували розробників обгортати вміст у ng-template для складних умов. Новий синтаксис control flow вирішує ці проблеми:
- Не потребує імпортів:
@if,@forта@switchвбудовані у фреймворк - JavaScript-подібний синтаксис: умови та цикли читаються як стандартний код
- Нативна підтримка
@else: більше немає потреби в посиланнях наng-templateдля гілок else - Кращий tree-shaking: невикористані блоки control flow мають нульовий вплив на бандл
Документація Angular рекомендує повністю приймати блоковий синтаксис у всіх нових проектах та поступово мігрувати існуючі кодові бази.
@if: Умовний рендеринг без ng-template
Блок @if умовно рендерить вміст на основі істинного виразу. На відміну від *ngIf, він безпосередньо підтримує гілки @else if та @else:
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 }>();
}Блок @if також підтримує аліасування змінних за допомогою ключового слова as, яке витягує значення з вкладених виразів:
<!-- Уникає повторного доступу до властивостей -->
@if (user().profile?.settings?.theme; as theme) {
<p>Поточна тема: {{ theme }}</p>
}Цей патерн особливо корисний при роботі з асинхронними даними або глибоко вкладеними об'єктами, оскільки аліасована змінна визначається лише коли умова істинна.
@for: Ітерація з обов'язковим виразом track
Блок @for ітерує по будь-якому ітерабельному об'єкту JavaScript з оптимізаціями для масивів. На відміну від *ngFor, він вимагає виразу 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) {
<div class="product-card">
<h3>{{ product.name }}</h3>
<p>{{ product.price | currency }}</p>
</div>
} @empty {
<p>Продукти недоступні</p>
}
`
})
export class ProductListComponent {
products = input.required<Product[]>();
}Вираз track є обов'язковим, оскільки дозволяє алгоритму порівняння Angular ідентифікувати елементи між циклами виявлення змін. Завдяки цьому фреймворк знає, які елементи DOM слід повторно використати, а які створити заново.
Доступ до контекстних змінних у @for
Блок @for надає кілька контекстних змінних:
@for (item of items(); track item.id; let idx = $index, first = $first, last = $last) {
<div [class.first-item]="first" [class.last-item]="last">
{{ idx + 1 }}. {{ item.name }}
</div>
}Доступні контекстні змінні:
$index- поточний індекс (починаючи з 0)$first- чи це перший елемент$last- чи це останній елемент$even- чи індекс парний$odd- чи індекс непарний$count- загальна кількість елементів у колекції
@switch: Множинне розгалуження без ng-container
Блок @switch обробляє сценарії з кількома умовами без необхідності вкладених елементів ng-container:
import { Component, input } from '@angular/core';
type NotificationType = 'success' | 'warning' | 'error' | 'info';
@Component({
selector: 'app-notification',
template: `
@switch (type()) {
@case ('success') {
<div class="alert alert-success">
<span class="icon-check"></span>
<ng-content />
</div>
}
@case ('warning') {
<div class="alert alert-warning">
<span class="icon-warning"></span>
<ng-content />
</div>
}
@case ('error') {
<div class="alert alert-error">
<span class="icon-error"></span>
<ng-content />
</div>
}
@default {
<div class="alert alert-info">
<span class="icon-info"></span>
<ng-content />
</div>
}
}
`
})
export class NotificationComponent {
type = input<NotificationType>('info');
}Блок @switch використовує строге порівняння (===), що усуває неочікувану поведінку, пов'язану з приведенням типів.
Вкладення блоків control flow
Блоки control flow можна вільно вкладати для створення складної логіки рендерингу:
@if (isLoading()) {
<app-skeleton-loader />
} @else {
@for (category of categories(); track category.id) {
<section class="category">
<h2>{{ category.name }}</h2>
@for (product of category.products; track product.id) {
@switch (product.availability) {
@case ('in_stock') {
<app-product-card [product]="product" />
}
@case ('pre_order') {
<app-preorder-card [product]="product" />
}
@default {
<app-out-of-stock-card [product]="product" />
}
}
} @empty {
<p>У цій категорії немає продуктів</p>
}
</section>
} @empty {
<p>Немає категорій для відображення</p>
}
}Оптимізації продуктивності з новим синтаксисом
Новий синтаксис control flow приносить значні покращення продуктивності:
Швидший Change Detection
Блоки @for з виразом track дозволяють Angular ефективніше порівнювати колекції. Фреймворк може пропускати перевірку елементів, які не змінилися, базуючись на ідентичності відстежуваного значення.
Краща мініфікація
Оскільки блоковий синтаксис не вимагає імпортів з CommonModule, невикористані блоки можуть бути повністю видалені під час production збірки.
Оптимізація @defer
Синтаксис control flow працює з @defer для ледачого завантаження:
@defer (on viewport) {
@for (item of heavyItems(); track item.id) {
<app-heavy-component [data]="item" />
}
} @placeholder {
<div class="placeholder">Завантаження...</div>
}Міграція зі структурних директив
Процес міграції простий завдяки вбудованій схемі:
ng generate @angular/core:control-flowСхема автоматично перетворює:
| Старий синтаксис | Новий синтаксис |
|---|---|
*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; trackBy: trackFn" | @for (item of items; track trackFn($index, item)) { } |
[ngSwitch] + *ngSwitchCase | @switch + @case |
Готовий до співбесід з Angular?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
Питання на співбесідах щодо Angular Control Flow
Нижче наведено набір питань, які часто задають на технічних співбесідах про новий синтаксис control flow.
Питання 1: Чому вираз track є обов'язковим у @for?
Відповідь: Вираз track є обов'язковим, оскільки надає алгоритму порівняння Angular унікальний ідентифікатор для кожного елемента в колекції. Це дозволяє фреймворку ефективно визначати, які елементи DOM слід повторно використати, оновити або видалити під час змін у колекції. Без відстеження Angular мусив би повторно рендерити весь список при кожній зміні, що суттєво впливало б на продуктивність.
Питання 2: Як @if обробляє глибоко вкладені опціональні властивості?
Відповідь: Блок @if підтримує аліасування змінних за допомогою ключового слова as, яке дозволяє витягти значення з вкладеного виразу та використовувати його в блоці. Синтаксис: @if (вираз; as аліас). Аліасована змінна доступна лише коли вираз істинний, що усуває потребу повторювати оператори опціонального ланцюжка в шаблоні.
Питання 3: Чим @switch відрізняється від *ngSwitch?
Відповідь: @switch вбудований у фреймворк і не вимагає імпортів. Він використовує нативний блоковий синтаксис замість директивних атрибутів. Усуває потребу в обгорткових елементах ng-container. Використовує строге порівняння (===), що запобігає неочікуваним співпадінням через приведення типів. Кожен @case та @default є незалежними блоками, що покращує читабельність коду.
Питання 4: Як отримати доступ до індексу та інших метаданих у @for?
Відповідь: Блок @for надає контекстні змінні через синтаксис let: @for (item of items; track item.id; let i = $index, f = $first). Доступні змінні: $index, $first, $last, $even, $odd та $count. Ці змінні можна присвоїти локальним аліасам і використовувати в блоці.
Питання 5: Чи можна використовувати @for з об'єктами Map і Set?
Відповідь: Так, блок @for ітерує по будь-якому об'єкту, що реалізує протокол ітератора JavaScript, включаючи Map, Set та генератори. Для Map ітерація повертає пари [ключ, значення], які можна деструктурувати в шаблоні.
Питання 6: Як працює @empty і коли він викликається?
Відповідь: Блок @empty відображається коли колекція в @for порожня (має нульову довжину) або коли ітерабельний об'єкт не повертає жодних елементів. Це вбудований еквівалент перевірки items.length === 0 та рендерингу альтернативного вмісту. Блок @empty є необов'язковим.
Питання 7: Які переваги продуктивності нового синтаксису control flow?
Відповідь: Новий синтаксис пропонує кілька переваг продуктивності: відсутність накладних витрат на імпорти (нуль додаткового коду для директив), кращий tree-shaking (невикористані шляхи коду усуваються), ефективніший change detection завдяки обов'язковому відстеженню, та можливість майбутніх оптимізацій компілятора, оскільки синтаксис парситься статично замість інтерпретації в runtime.
Найкращі практики для синтаксису Control Flow
При впровадженні нового синтаксису control flow варто дотримуватися кількох принципів:
- Завжди використовуйте унікальні ідентифікатори в track - надавайте перевагу
track item.idзамістьtrack $indexдля колекцій, що можуть змінюватися - Використовуйте @empty для кращого UX - завжди визначайте стан порожнього списку для кращого досвіду користувача
- Уникайте складної логіки у виразах - переносьте складні обчислення до компонента
- Застосовуйте аліасування для вкладених властивостей - використовуйте
asдля глибоко вкладених опціональних виразів - Мігруйте поступово - обидва синтаксиси можуть співіснувати, тому можна мігрувати файл за файлом
Висновок
Синтаксис control flow в Angular представляє фундаментальну зміну в способі написання шаблонів. Блоки @if, @for та @switch пропонують інтуїтивніший синтаксис, натхненний JavaScript, усувають потребу імпорту CommonModule та забезпечують кращу продуктивність завдяки обов'язковому відстеженню та оптимізаціям компілятора. Для команд, що розпочинають нові проекти Angular, новий синтаксис має бути вибором за замовчуванням. Для існуючих проектів автоматична міграція за допомогою схеми ng generate @angular/core:control-flow забезпечує плавний перехід без ризику регресії.
Чи знайдеш ти помилку в Angular?
Справжній фрагмент коду, прихована помилка, одна спроба на день. Щоб спробувати, акаунт не потрібен.

Автор:
Anthony Fillion-MailletЗасновник SharpSkill
Fullstack-розробник понад 10 років. Керує SharpSkill і відповідає за все, що тут публікується.
Оновлено 3 вересня 2026 р.
Теги
Поділитися
Пов'язані статті

Просунутий Dependency Injection в Angular 2026: Providers, Tokens та Питання на Співбесідах
Комплексний посібник з просунутих механізмів Dependency Injection в Angular. Providers, InjectionToken, ієрархія інжекторів та найпоширеніші питання на технічних співбесідах.

NgRx Signal Store vs Класичний NgRx у 2026: Який Обрати?
Комплексне порівняння NgRx Signal Store та класичного NgRx для управління станом в Angular. Практичні приклади коду та рекомендації на 2026 рік.

RxJS в Angular 2026: оператори, Subject'и та interop із Signals
RxJS в Angular 2026: опануйте оператори, Subject'и та патерни interop із Signals, які розробники використовують у продакшені, плюс найпоширеніші питання співбесід.