Ласкаво просимо до Angular 19! Це останнє оновлення приносить безліч нових функцій і вдосконалень, спрямованих на спрощення розробки та підвищення ефективності. Від інноваційних реактивних примітивів, таких як linkedSignal і API ресурсів, до експериментального Incremental Hydration і покращень у Angular Language Service, Angular 19 наповнений інструментами для прискорення роботи ваших додатків. Пориньте в наш всебічний огляд, щоб дізнатися всі захоплюючі оновлення та дізнатися, як вони можуть підняти ваші проекти на новий рівень.
Новий (експериментальний) реактивний примітив: linkedSignal
linkedSignal — це записуваний сигнал, який реагує на зміни в вихідному сигналі і може скидатись на основі обчисленого значення.
export declare function linkedSignal(options: {
source: () => S;
computation: (source: NoInfer, previous?: {
source: NoInfer;
value: NoInfer;
}) => D;
equal?: ValueEqualityFn>;
}): WritableSignal;
Початкове значення сигналу обчислюється за допомогою функції computation
, після чого значення сигналу можна змінювати вручну за допомогою методу set
. Коли значення вихідного сигналу змінюється, значення зв’язаного сигналу буде перераховано знову за допомогою методу computation
.
Розглянемо приклад для кращого розуміння концепції:
protected readonly colorOptions = signal([{
id: 1,
name: 'Red',
}, {
id: 2,
name: 'Green',
}, {
id: 3,
name: 'Blue',
}]);
protected favoriteColorId = linkedSignal({
source: this.colorOptions,
computation: (source, previous) => {
if(previous?.value) {
return source.some(color => color.id === previous.value) ? previous.value : null;
}
return null;
}
});
protected onFavoriteColorChange(colorId: number): void {
this.favoriteColorId.set(colorId);
}
protected changeColorOptions(): void {
this.colorOptions.set([
{ id: 1, name: 'Red' },
{ id: 4, name: 'Yellow' },
{ id: 5, name: 'Orange' }
]);
}
У цьому прикладі colorOptions
зберігає список кольорів, які користувач може вибрати. favoriteColorId
представляє вибраний колір користувача. Пов’язаний сигнал перераховує своє значення щоразу, коли змінюється список colorOptions
.
Новий (експериментальний) API: resource
Angular вводить новий експериментальний API під назвою resource()
, який керує асинхронними операціями. Цей API допомагає запобігти гонці умов, відслідковує стан завантаження, обробляє помилки, оновлює значення вручну і викликає завантаження даних за потребою.
Ось приклад використання API ресурсу:
fruitId = signal('apple-id-1');
fruitDetails = resource({
request: this.fruitId,
loader: async (params) => {
const fruitId = params.request;
const response = await fetch(`https://api.example.com/fruit/${fruitId}`, { signal: params.abortSignal });
return await response.json() as Fruit;
}
});
protected isFruitLoading = this.fruitDetails.isLoading;
protected fruit = this.fruitDetails.value;
protected error = this.fruitDetails.error;
protected updateFruit(name: string): void {
this.fruitDetails.update((fruit) => fruit ? { ...fruit, name } : undefined);
}
protected reloadFruit(): void {
this.fruitDetails.reload();
}
protected onFruitIdChange(fruitId: string): void {
this.fruitId.set(fruitId);
}
За допомогою API ресурсу:
- Параметр запиту зв'язує ресурс з вхідним сигналом (у нашому випадку
fruitId
). - Функція завантажувача асинхронно отримує дані.
- Ви можете отримати доступ до сигналів, таких як
isLoading
,value
іerror
. - Ви можете перезавантажити дані або оновити локальний стан ресурсу за допомогою методів, таких як
reload
іupdate
.
Ресурс автоматично перезавантажиться, якщо зміниться сигнал запиту.
RxJS Interop
Angular тепер надає аналог методу ресурсу, званий rxResource
.
Ця версія використовує Observable як функцію завантаження, зберігаючи всі інші властивості як сигнали.
fruitDetails = rxResource({
request: this.fruitId,
loader: (params) => this.httpClient.get(`https://api.example.com/fruit/${params.request}`)
});
Оновлення функції effect()
У Angular 19 функція effect()
зазнала важливих оновлень на основі відгуків від спільноти. Однією з основних змін є видалення прапорця allowSignalWrites
, який раніше використовувався для обмеження того, коли сигнали можуть бути встановлені в effect()
. Тепер сигнали можна встановлювати за замовчуванням, що спрощує реалізацію оновлень.
effect(
() => {
console.log(this.users());
}
);
Крім того, ефекти тепер виконуються як частина циклу виявлення змін у ієрархії компонентів, а не як мікрозавдання. Це покращує таймінг ефектів, забезпечуючи їх виконання в більш передбачуваному порядку.
Нова функція рівності в RxJS Interop
Функція toSignal
в Angular тепер підтримує користувацьку функцію рівності, що дає розробникам більше контролю над тим, як порівняння значень ініціює оновлення. Це допомагає оптимізувати продуктивність, гарантуючи, що оновлення відбуваються лише тоді, коли відбуваються значущі зміни.
// Створюємо Subject для емісії значень масиву
const arraySubject$ = new Subject();
// Визначаємо користувацьку функцію рівності для порівняння масивів за їх вмістом
const arraysAreEqual = (a: number[], b: number[]): boolean => {
return a.length === b.length && a.every((value, index) => value === b[index]);
};
// Перетворюємо Subject на сигнал з користувацькою функцією рівності
const arraySignal = toSignal(arraySubject$, {
initialValue: [1, 2, 3],
equals: arraysAreEqual,
});
Нова функція afterRenderEffect
Функція afterRenderEffect
є експериментальним API в Angular, яке обробляє побічні ефекти, які повинні виконуватись лише після того, як компонент завершить рендеринг. Ця функція дозволяє вам реагувати на зміни стану лише після оновлення DOM.
counter = signal(0);
constructor() {
afterRenderEffect(() => {
console.log('after render effect', this.counter());
});
afterRender(() => {
console.log('after render', this.counter());
});
}
afterRenderEffect
відслідковує залежності і виконується після кожного циклу рендерингу, тоді як afterRender
виконується після кожного циклу рендерингу незалежно від залежностей.
Новий синтаксис змінних шаблону @let
Angular представив синтаксис @let
в версії 18.1, який став стабільним в версії 19. Ця функція спрощує визначення і повторне використання змінних у шаблонах, що робить їх зручними для зберігання і посилання на вирази.
@let userName = 'Jane Doe';
Welcome, {{ userName }}
@let greeting = 'Hello, ' + userInput.value;
{{ greeting }}
@let userData = userObservable$ | async;
User details: {{ userData.name }}
``` Змінні, визначені через `@let`, є лише для читання і мають область видимості в поточному шаблоні та його нащадках.
## Експериментальна Інкрементальна Гідратація
Angular 19 вводить експериментальну функцію під назвою Інкрементальна Гідратація. Ця функція покликана покращити час завантаження та інтерактивність шляхом вибіркової гідратації частин серверно-рендереного додатку на клієнті.
Щоб активувати цю функцію, додайте наступну конфігурацію:
export const appConfig: ApplicationConfig = {
providers: [
provideClientHydration(
withIncrementalHydration()
)
]
};
```
Інкрементальна Гідратація підтримує кілька тригерів, таких як:
- idle
- interaction
- immediate
- timer(ms)
- hover
- viewport
- never (залишається дегідратованим безкінечно)
- when {{ умова }}
Ця функція покращує ефективність додатків, активуючи лише необхідні компоненти спочатку.
Новий вхід routerOutletData для RouterOutlet
У Angular 19 додано новий вхід routerOutletData
для RouterOutlet
, що забезпечує спрощений спосіб для батьківських компонентів передавати дані своїм дочірнім компонентам, які маршрутизуються через цей outlet.
Коли routerOutletData
встановлено, відповідні дані стають доступними в дочірніх компонентах через токен ROUTER_OUTLET_DATA
, який використовує тип Signal. Такий підхід дозволяє динамічно оновлювати дані, забезпечуючи, щоб зміни в вхідних даних автоматично відображалися в дочірньому компоненті, усуваючи необхідність у статичних присвоєннях.
Батьківський компонент:
Дочірній компонент, що маршрутується через Outlet:
export class ChildComponent {
readonly routerOutletData: Signal = inject(ROUTER_OUTLET_DATA);
}
RouterLink, що приймає UrlTree
З версії 18.1, вхід директиви RouterLink
також приймає об'єкт типу UrlTree
.
Home
Це дозволяє передавати всі додаткові параметри (наприклад, параметри запиту, стратегію обробки параметрів запиту, relativeTo тощо) безпосередньо в об'єкт UrlTree
.
Важливо: При спробі передати об'єкт UrlTree
через вхід routerLink
, одночасно використовуючи інші вхідні параметри, такі як queryParams
або fragment
, Angular виведе помилку, що пояснює, що це не дозволено:
‘Неможливо налаштувати
queryParams
абоfragment
, коли використовується об'єктUrlTree
як значення для входуrouterLink
.’
Стратегія обробки параметрів запиту за замовчуванням
Тепер ви можете налаштувати стандартну стратегію обробки параметрів запиту для всіх маршрутів безпосередньо в конфігурації provideRouter()
.
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes, withRouterConfig({ defaultQueryParamsHandling: 'preserve' }))
]
};
Хоча за замовчуванням Angular використовує стратегію заміни, ви можете вибрати стратегію збереження або злиття. Раніше цю стратегію можна було встановлювати індивідуально для кожної навігації, або через RouterLink
, або через опції router.navigate
.
Standalone за замовчуванням
З випуском Angular v19 параметр standalone: true
стане значенням за замовчуванням для компонентів, директив і труб.
Standalone компонент:
@Component({
imports: [],
selector: 'home',
template: './home-component.html',
// standalone в Angular 19!
})
export class HomeComponent { ... }
Для не-standalone компонентів потрібно буде явно вказати прапорець:
@Component({
selector: 'home',
template: './home-component.html',
standalone: false
// non-standalone в Angular 19!
})
export class HomeComponent { ... }
Це спрощує Angular, роблячи його більш доступним для нових розробників і покращує такі функції, як lazy loading і компонування компонентів.
Нові міграції для API Standalone та ін'єкцій
Angular запровадив необов'язкову міграцію для покращення ін'єкції залежностей, переміщуючи від ін'єкцій, заснованих на конструкторах, до використання функції inject()
.
До міграції:
constructor(private productService: ProductService) {}
Після міграції:
private productService = inject(ProductService);
Після міграції можуть виникнути проблеми з компіляцією, особливо в тестах, де екземпляри створюються безпосередньо.
Міграційна утиліта надає кілька опцій для обробки абстрактних класів, зворотно сумісних конструкторів і налаштувань, що можуть бути нульовими, щоб забезпечити плавний перехід.
Крім того, окрема міграція сприяє lazy loading (ліниве завантаження) самостійних компонентів у конфігураціях маршрутизації, перетворюючи прямі посилання на компоненти в динамічні імпорти для оптимізації продуктивності.
До міграції:
{
path: 'products',
component: ProductsComponent
}
Після міграції:
{
path: 'products',
loadComponent: () => import('./products/products.component').then(m => m.ProductsComponent)
}
Ініціалізатори
Angular v19 вводить нові допоміжні функції: provideAppInitializer
, provideEnvironmentInitializer
, і providePlatformInitializer
, які спрощують процес налаштування ініціалізаторів.
Приклад:
export const appConfig: ApplicationConfig = {
providers: [
provideAppInitializer(() => {
console.log('app initialized');
})
]
};
Ці функції надають більш чисті альтернативи традиційним токенам APP_INITIALIZER
, ENVIRONMENT_INITIALIZER
, і PLATFORM_INITIALIZER
, що робить ініціалізацію простішою та зрозумілішою.
Автоматичний виклик flush()
у fakeAsync
В Angular v19 функція flush()
у тестах fakeAsync()
викликається автоматично після завершення тесту. Це усуває необхідність вручну викликати flush()
або discardPeriodicTasks()
, щоб очистити невиконані асинхронні завдання, спрощуючи код тестів.
До Angular v19:
it('async test description', fakeAsync(() => {
// ...
flush();
}));
Після Angular v19:
it('async test description', fakeAsync(() => {
// Тепер не потрібно вручну викликати flush()
}));
Нові діагностики Angular
Розширені діагностики Angular — це реальний час перевірки коду, яка виходить за межі стандартних помилок і попереджень, фіксуючи більш дрібні проблеми, такі як невикористовувані функції, відсутні імпорти та порушення найкращих практик.
Нові діагностики в Angular v19:
- Невикликані функції: Виявляє випадки, коли функція використовується в прив'язці події, але не викликається, зазвичай через відсутність дужок у шаблоні.
- Невикористовувані самостійні імпорти: Виявляє випадки, коли самостійні компоненти, директиви чи трубки імпортуються, але не використовуються в модулі чи компоненті.
Строгий прапорець для Standalone
Angular вводить прапорець strictStandalone
в angularCompilerOptions
для забезпечення використання лише самостійних компонентів, директив та трубок. Цей прапорець гарантує, що не standalone компоненти, директиви та трубки не можуть бути використані, коли прапорець увімкнено.
Підтримка Playwright у Angular CLI
З Angular v19, коли ви виконуєте команду ng e2e
без налаштованої цілі e2e, вам буде запропоновано вибрати пакет e2e. Playwright тепер є одним із доступних варіантів.
Щоб додати підтримку Playwright до вашого проєкту, використовуйте таку команду:
ng add playwright-ng-schematics
Підтримка TypeScript
Angular v19 додає підтримку TypeScript 5.6, при цьому підтримка версій нижче 5.5 більше не надається.
Деякі значущі функції в TypeScript 5.6 включають:
Інферовані предикати типів: TypeScript автоматично звужує типи в тих місцях, де раніше були необхідні предикати.
Приклад:
const availableProducts = productIds
.map(id => productCatalog.get(id))
.filter(product => product !== undefined);
Звуження потоку виконання для постійних індексованих доступів: TypeScript звужує вирази на кшталт obj[key], коли і obj, і key є константами.
Приклад:
function logUpperCase(key: string, dictionary: Record): void {
if (typeof dictionary[key] === 'string') {
console.log(dictionary[key].toUpperCase());
}
}
Підтримка ізольованих модулів TypeScript
Angular v18.2 ввів підтримку ізольованих модулів TypeScript, що дозволяє прискорити побудову виробничих версій за рахунок транспіляції коду через збірник.
Щоб увімкнути ізольовані модулі, оновіть вашу конфігурацію TypeScript (tsconfig.json):
"compilerOptions": {
"isolatedModules": true
}
Покращення Angular Language Service
Angular Language Service тепер підтримує нові функції, такі як:
- Діагностика Angular для невикористовуваних самостійних імпортів.
- Міграція з @Input на signal-input.
- Автодоповнення в шаблонах для директив, які ще не були імпортовані.
Конфігурація маршруту на сервері (експериментальна)
Angular вводить новий API для конфігурації маршруту на сервері, щоб покращити гнучкість гібридного рендерингу. Це дозволяє розробникам визначити, як повинні рендеритись конкретні маршрути (на сервері, попередньо рендеритись або на клієнті).
Приклад:
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRouteConfig: ServerRoute[] = [
{ path: '/login', renderMode: RenderMode.Server },
{ path: '/fruits', renderMode: RenderMode.Prerender },
{ path: '/**', renderMode: RenderMode.Client }
];
Підсумок
Angular v19 вводить ряд потужних оновлень, спрямованих на підвищення продуктивності додатків, оптимізацію реактивності та покращення контролю для розробників. Завдяки таким функціям, як покращена ін'єкція залежностей, покращене lazy loading і новітнім експериментальним можливостям, Angular продовжує еволюціонувати, забезпечуючи більшу гнучкість і ефективність у майбутніх версіях.
Створімо щось велике разом!
У Sparkle Web ми спеціалізуємося на інноваційних технічних рішеннях, що дозволяють вашому бізнесу зростати та масштабуватися. Якщо ви шукаєте надійного та кваліфікованого партнера для розвитку ваших проєктів, ми тут, щоб допомогти!
Незалежно від того, чи це розробка повного стеку, розробка додатків на Flutter, хмарні рішення чи веб-тестування, наша команда експертів готова співпрацювати з вами для створення значущих результатів.
Зв'яжіться з нами сьогодні, щоб обговорити, як ми можемо співпрацювати та втілити вашу ідею в реальність!
Перекладено з: Angular 19: The Ultimate Guide for Developers in 2025