Angular
Angular — фреймворк Google на TypeScript, що постачає весь фронтенд-стек і між мажорними версіями сам оновлює ваш код автоматичними міграціями. Цей стек — компоненти, впровадження залежностей, маршрутизація, форми, HTTP, тестування й збірка, обрані й випущені разом. Між 2022 і 2026 роками він замінив більшу частину того, як на ньому писали: standalone-компоненти замість NgModules, сигнали замість zone.js і OnPush за замовчуванням. Сторінка починається з кожного будівельного блоку на одному екрані — сучасний спосіб поруч із тим, який він замінив; далі — релізи й підтримка, впровадження залежностей, виявлення змін, сигнали й RxJS, форми й безпека та п’ять задокументованих кейсів.
- Поточна версія
- 22.2 · вересень 2026
- Мова
- TypeScript 6.0+, обов’язково
- Мажорні релізи
- Раз на рік, з v22
Angular на одному екрані: кожен будівельний блок — тоді й тепер
Застосунок на Angular складається з невеликої кількості видів речей: компонентів, сервісів, від яких вони залежать, шаблонів, входів і виходів, і механізму, що вирішує, коли оновлювати екран. Майже в кожного з них тепер є сучасний спосіб і старіший, який досі працює, — і більшість матеріалів в інтернеті вчить старішого. Тут усе це одразу. Таблиця перелічує кожну роботу, те, як її робить Angular 22 (вересень 2026), що саме цей спосіб замінив, і версію, в якій він став стабільним. Це ще й найшвидший спосіб зрозуміти, який Angular описує туторіал, кодова база чи кандидат на співбесіді.
| Робота | Сучасний спосіб | Що він замінив | З версії |
|---|---|---|---|
| Організація коду | Standalone-компоненти, що самі перелічують свої imports | NgModules, що оголошують групи компонентів | v15 · типово v19 |
| Отримання залежності | inject() у полі чи функції | Параметри конструктора — досі підтримуються | v14 |
| Стан компонента | signal() | Звичайні поля, які zone.js перевіряє після кожної події | v17 |
| Похідний стан | computed() | Геттери чи значення, що перераховуються в ngOnChanges | v17 |
| Стан, що йде за входом, але редагується | linkedSignal() | Копіювання входу в поле в ngOnChanges | v20 |
| Реакція на стан поза шаблоном | effect() — ощадливо | ngOnChanges або subscribe в ngOnInit | v20 |
| Входи | input(), input.required() | Декоратори @Input() | v19 |
| Виходи | output() | @Output() з EventEmitter | v19 |
| Двобічне зв’язування | model() | @Input() плюс @Output(), чия назва закінчується на Change | v19 |
| Доступ до дочірніх елементів | viewChild(), contentChild() | @ViewChild, @ContentChild | v19 |
| Умови й цикли в шаблонах | @if, @for (…; track …), @switch | *ngIf, *ngFor, *ngSwitch — застарілі з v20 | v18 |
| Локальна змінна в шаблоні | @let | Трюк *ngIf="data as d" | v19 |
| Пізніше завантаження частини сторінки | Блоки @defer | Лінивий маршрут чи написаний вручну динамічний імпорт | v18 |
| Завантаження даних | resource(), httpResource() | HttpClient плюс subscribe плюс прапорці завантаження й помилки вручну | v22 |
| Форми | Signal Forms, form() | Reactive Forms і форми на шаблонах — жодні не застарілі | v22 |
| Що запускає перевірку | Zoneless: зміна сигналу, подія в шаблоні, markForCheck | zone.js, що патчить кожен async-API браузера | v20.2 · типово v21 |
| Що перевіряється | OnPush, за замовчуванням | Стратегія Default, тепер названа Eager | типово v22 |
| Транспорт HTTP | fetch | XMLHttpRequest — лишився як withXhr() для прогресу вивантаження | типово v22 |
| Серверний рендеринг | Інкрементальна гідратація: @defer (hydrate on …) | Гідратація всієї сторінки одразу — або, у старіших версіях, її перебудова | v20 · типово v22 |
| Юніт-тести | Vitest | Karma і Jasmine | типово v21 |
| Завершення підписки | takeUntilDestroyed() або async pipe | Subject, завершений у ngOnDestroy | v19 |
Усе вирішено — і оновлюється за вас
Почати проєкт на React означає обрати маршрутизатор, шар даних, бібліотеку форм, підхід до стилів і збірку ще до першої фічі. Почати проєкт на Angular означає виконати одну команду й отримати все це — обране, інтегроване й випущене разом. Чи звучить це як полегшення, чи як клітка — і є чесною перевіркою, чи пасує вам фреймворк. Наслідок, що важить у роках, а не тижнях, — однорідність: дві кодові бази на Angular, написані різними командами, суттєво схожі, тож інженер, що переходить між ними, швидко стає продуктивним.
Другий наслідок незвичний для фреймворку: Angular бере на себе відповідальність за те, щоб ваш код рухався вперед. ng update запускає міграції — скрипти, що переписують ваш код під нову версію. Коли v21 перестав за замовчуванням використовувати zone.js, міграція додала в наявні застосунки provideZoneChangeDetection(), щоб вони працювали, як раніше. Коли v22 зробив кожен компонент без явної стратегії OnPush, міграція додала ChangeDetectionStrategy.Eager саме таким компонентам, тож оновлення тихо не змінило поведінку жодного з них. Нове налаштування діє для нового коду; стара поведінка зберігається — записана явно — там, де на неї вже покладалися.
Міграції допомагають лише всередині вікна підтримки, а вікно коротке. Кожна мажорна версія якийсь час «активна» — отримує виправлення й дрібні можливості, — а потім переходить у довгострокову підтримку, коли випускають лише критичні виправлення й патчі безпеки. Усе старіше не отримує нічого. До v22 мажорна версія виходила раз на пів року; з v22 — раз на рік, із чотирма-шістьма мінорними релізами між ними, тож кожне вікно довше, а кожне оновлення більше.
| Версія | Випущено | Активна до | Патчі безпеки до |
|---|---|---|---|
| v22 | 3 черв. 2026 | черв. 2027 | черв. 2028 |
| v21 | 19 лист. 2025 | 3 черв. 2026 | черв. 2027 |
| v20 | 28 трав. 2025 | 19 лист. 2025 | 28 лист. 2026 |
| v2 – v19 | 2016 – 2024 | — | Жодних |
Angular
- Роутер, форми, HTTPHyperText Transfer Protocol — протокол вебуПротокол, яким спілкуються браузер і сервер: клієнт надсилає метод і адресу, сервер відповідає кодом стану й тілом. Між запитами він нічого не памʼятає — кожен запит стоїть сам по собі, тому все, що треба памʼятати, передається явно.Усі терміни, тестування — надані та інтегровані
- TypeScriptJavaScript із перевіркою типівJavaScript плюс опис того, що саме функція приймає й повертає, — і цей опис перевіряється в редакторі ще до запуску. У браузер він не потрапляє: перед складанням його компілюють назад у звичайний JavaScript, тож типи — це інструмент розробки, і не більше.Докладніше в статті →Усі терміни і впровадження залежностей не є опційними
- Автоматичні міграції між мажорними версіями
- Велике навантаження понять на старті, далі однорідність
- Шаблони, скомпільовані заздалегідь
React
- Модель компонентів; решта — ваш вибір або фреймворку
- TypeScript опційний, впровадження залежностей нетипове
- Оновлення узгоджуються між незалежними пакетами
- Мале ядро; складність накопичується у виборі
- JSXрозмітка всередині кодуСинтаксис, що дозволяє писати розмітку прямо в JavaScript. Це не HTML усередині коду, а скорочення: перед запуском кожен тег перетворюється на звичайний виклик функції.Докладніше в статті →Усі терміни — вигляд є звичайним JavaScript
Вибір рідко буває технічним. Angular пасує організації з багатьма командами, довгоживучими продуктами й плинністю кадрів, де одна відповідь на питання цінніша за найкращу відповідь на кожне. React пасує команді, яка хоче зібрати власний стек і здатна нести ціну його підтримки. Обидва будують ті самі застосунки; різниця в тому, хто ухвалює рішення і хто з ними живе.
Впровадження залежностей: місце надання вирішує, скільки екземплярів
Компонент не створює того, що йому потрібно. Він просить — private http = inject(HttpClient), — і фреймворк дає йому екземпляр, а компонент не знає, звідки той узявся й хто ще ним користується. Об’єкт, що зберігає екземпляри й видає їх, називається інжектором, і в Angular їх ціле дерево.
Виграш — у підміні. Тест замінює справжній HTTP-клієнт підробкою зміною одного провайдера, а не патчем імпорту. Компоненту, що пише в лог через впроваджений логер, можна дати інший логер в іншому середовищі. Ціна — опосередкованість: читаючи компонент, ви бачите, від чого він залежить, але не бачите, яка реалізація прийде. Цей компроміс вартий того, коли підміна справді використовується, і є чистою накладною витратою, коли ні: сервіс, впроваджений в одному місці й ніде не замінений, не дав нічого і зробив код на один стрибок важчим для читання.
Коли компонент щось просить, Angular шукає спершу у власному інжекторі компонента, потім у батьківському, вгору деревом компонентів, а тоді — в кореневому інжекторі застосунку. Перемагає перший, у кого є провайдер. Якщо ні в кого немає, запит падає з NG0201: No provider for … found — помилкою, яку кожен розробник на Angular зустрічає першого ж тижня, зазвичай тому, що сервіс ніде не зареєстрували. Тож місце, де ви реєструєте сервіс, вирішує, скільки екземплярів існує і як довго живе кожен:
| Де надано | Скільки екземплярів | Живе до | Підходить для |
|---|---|---|---|
providedIn: "root" | Один на весь застосунок | Вкладку закрили | Сервіси без стану, клієнт API, користувач, що увійшов, кеші |
providers компонента | Один на кожен екземпляр цього компонента | Цей екземпляр знищено | Стан одного віджета, однієї форми, одного покрокового майстра |
Як фреймворк знаходить, що робити
Angular має вирішувати, коли порівнювати шаблон кожного компонента з його даними й оновлювати екран. Це порівняння називається виявленням змін. Більшу частину життя Angular відповідь на «коли» давав zone.js — бібліотека, що патчить кожен асинхронний APIApplication Programming Interface — контракт між програмамиПравила, за якими одна програма звертається до іншої: які запити можна надіслати, у якому вигляді й що прийде у відповідь. Для того, хто звертається, це контракт — усе, що за ним, лишається чорною скринькою, і саме тому другий бік можна переписати, не зламавши вас.Докладніше в статті →Усі терміни браузера (таймери, слухачі подій, мережеві запити), щоб Angular дізнавався щоразу, коли будь-що завершується. За цим сигналом Angular обходив дерево компонентів і переобчислював вирази в шаблонах.
Це менш марнотратно, ніж звучить. Angular компілює шаблони заздалегідь, тож перевірка виразу — це порівняння властивостей, а не інтерпретація, і тисячі таких перевірок швидкі. Проблемою це стає в масштабі та в певних формах: велике дерево, шаблон, що викликає функцію на кожній перевірці, або подія, яка сипле безперервно, як прокрутка чи рух миші над графіком.
Першою відповіддю був OnPush, і схема показує, що він дає. Компонент, позначений OnPush, перевіряється, лише коли один із його входів отримує нове посилання, коли спрацьовує подія, прив’язана в його власному шаблоні, коли змінюється сигнал, який читає його шаблон, або коли хтось викликає markForCheck — а async pipe робить це за вас. Усе інше пропускається разом із піддеревом. Ціна перестає залежати від розміру застосунку й починає залежати від того, де сталася зміна, — за умови, що входи замінюють, а не змінюють на місці; тому OnPush і незмінні оновлення завжди приходять разом. З v22 новий компонент є OnPush, якщо не сказано інакше; стара поведінка, що перевіряє все, тепер називається Eager.
Zoneless: знати замість здогадуватися
zone.js відповідає на питання «чи щось завершилося?», а чесна відповідь майже завжди «так»: таймер у скрипті аналітики, рух миші, який обробила бібліотека графіків, запит опитування, що нічого не змінив. Кожне з них запускало перевірку. Сигнали дають Angular поставити краще питання — «чи змінилося щось, що читають шаблони?», — бо сигнал знає, хто його прочитав. Zoneless-Angular, стабільний з v20.2 і типовий для нових застосунків з v21, повністю відмовляється від zone.js і запускає перевірку лише на зміну сигналу, на подію, прив’язану в шаблоні, або на явний markForCheck.
Практичний ефект — менше JavaScript у збірці, жодних пропатчених API браузера й строго менше роботи на кожну взаємодію. Ламається лише код, що покладався на те, що zone.js помітить зміну, про яку ніхто не оголосив, — звичайне поле, присвоєне всередині setTimeout в OnPush- чи zoneless-компоненті. Виправлення в кожному випадку те саме: тримайте це значення в сигналі.
Сигнали для стану, RxJS для подій у часі
Сигнал — це значення, яке запам’ятовує, хто його прочитав, подібно до ref у Vue. signal() тримає значення, яке ви задаєте; computed() виводить значення з інших сигналів — ліниво й лише тоді, коли ті змінюються; linkedSignal() іде за джерелом, але його можна задати й вручну, — як-от обраний пункт, що скидається, коли змінюється список. Входи теж сигнали: name = input<string>() читається як this.name(), тож усе похідне від входів — це computed, і більша частина того, що раніше робив ngOnChanges, зникає.
З effect() треба обережно, і порада Angular збігається з порадою React щодо useEffect: він для синхронізації з чимось поза графом сигналів — локальним сховищем, бібліотекою графіків, логом, — а не для того, щоб тримати один шматок стану в ногу з іншим. Effect, що задає сигнал, — це computed, написаний довгим шляхом, із миттю між ними, коли обидва не згодні.
Завантаження даних отримало власний API на сигналах, стабільний з v22. httpResource(() => "/api/orders/" + this.id()) повертає об’єкт, чиї value, status і error — сигнали, із шістьма статусами: idle, loading, reloading, resolved, error і local, де останній означає, що значення задали вручну. Коли id змінюється, поки запит ще в дорозі, ресурс його скасовує. Це прибирає за самою конструкцією перегони, в яких повільна стара відповідь перезаписує швидку нову, — ті перегони, які сторінки про React і Vue розв’язують вручну.
Де RxJS досі на своєму місці
RxJS моделює значення, що приходить багато разів, — потік — і дає оператори, щоб потоки перетворювати, поєднувати, затримувати й скасовувати. Події маршрутизатора й зміни значень форм в Angular — потоки, тож ви зустрінете його незалежно від того, чи шукали. Свою складність він виправдовує в координації в часі: поле пошуку, що чекає паузи в наборі, скасовує попередній запит на кожне нове натискання, ігнорує відповіді, що прийшли не по черзі, і повторює спробу при збої, — це чотири оператори й приблизно шість рядків. Написане вручну, це тридцять рядків із багом у скасуванні.
Більша частина цієї сили — в одному рішенні: що робити із запитом, який уже виконується, коли приходить нове значення. RxJS має для цього чотири оператори, і вибір не того дає баг, зовсім не схожий на свою причину.
| Оператор | Запит, що вже виконується | Для чого | Не на своєму місці |
|---|---|---|---|
| switchMap | Скасовується; важить лише останній | Пошук під час набору, параметр маршруту | На збереженнях: скасоване збереження — втрачений запис |
| mergeMap | Лишається; усі йдуть паралельно, відповіді в будь-якому порядку | Незалежні вивантаження, логування | На пошуку: стара відповідь може прийти останньою |
| concatMap | Лишається; новий чекає своєї черги | Збереження, що мають дійти до сервера по черзі | На пошуку: черга відповідей, які нікому не потрібні |
| exhaustMap | Лишається; нове значення ігнорується | Кнопка оплати чи надсилання, натиснута двічі | На пошуку: набір ігнорується, поки йде запит |
Шкодить RxJS там, де значення існує по одному за раз. BehaviorSubject із поточним користувачем — це потік з одного елемента, загорнутий у механізм, розрахований на багато, і кожен споживач мусить підписатися, відписатися й обробити початковий стан. Сигнали пасують цій формі краще, і вони задумані жити поруч: сигнали для стану, RxJS для подій у часі, а toSignal() і toObservable() — для перетворення між ними.
Форми й захист, який ви отримуєте за замовчуванням
Форми — найсильніша територія Angular, і з v22 є три способи їх будувати. Жоден не застарілий, а різняться вони тим, де живе модель форми:
| Підхід | Де живе модель | Підходить для |
|---|---|---|
| На шаблонах | У шаблоні, зв’язана через ngModel | Форма входу, поле пошуку |
| Reactive Forms | У класі, як об’єкти FormGroup і FormControl, типізовані з v14 | Наявні застосунки, форми, що будуються під час виконання |
| Signal Forms | У сигналі з даними, а правила валідації — у схемі | Новий код на v22 — експериментальні у v21, публічний API з v22 |
Безпека — те, що ви отримуєте, не просячи, і варто точно знати, що вона покриває. Angular вважає кожне значення, прив’язане в шаблоні, недовіреним. Текст у {{ }} екранується, тож коментар із <script> з’являється як текст. Значення, прив’язане до [innerHTML], санітизується — скрипти й небезпечні атрибути вирізаються, — а URL в href і src перевіряються. Шаблони компілюються під час збірки застосунку, тож у продакшені в браузері не працює компілятор шаблонів, до якого міг би дістатися ввід користувача. А HttpClient надсилає токен захисту від підробки запитів — читає його з XSRF-TOKEN і відправляє в заголовку X-XSRF-TOKEN — у запитах, що змінюють дані, лише на ваш власний origin, і серверу лишається одне: перевірити його.
П’ять кейсів і те, чого в кожному бракувало
Кожен кейс нижче задокументовано у власних журналах змін, посібниках чи бюлетенях безпеки Angular. Разом вони пояснюють форму фреймворку сьогодні — чому він так багато вкладає в міграції, чому шаблони компілюються до того, як потрапляють до користувача, і чому версія, на якій ви працюєте, важить не менше за код, який ви пишете.
| Кейс | Що сталося | Чого бракувало |
|---|---|---|
| AngularJS → Angular, 2014–2021 | Angular 2 був новим фреймворком зі старою назвою, оголошеним без шляху оновлення | Шлях міграції — причина, з якої існує ng update |
| Пісочниця виразів, 2016 | AngularJS прибрав пісочницю, яку команди помилково вважали межею безпеки | Правило, що користувачі ніколи не пишуть шаблонів, — тепер його забезпечують скомпільовані шаблони |
| NgModules, 2016–2024 | Додані за п’ять тижнів до 2.0, вони вісім років були найважчим поняттям для новачків | Компілятор, здатний прочитати кожен компонент окремо |
| View Engine → Ivy, 2020–2023 | Рушій рендерингу замінили; бібліотеки, зібрані під старий, перестали працювати у v16 | Залежності, що рухаються так само швидко, як фреймворк |
| CVE-2025-66035, лист. 2025 | HttpClient надсилав токен захисту на чужі хости; виправлення вийшло лише для підтримуваних версій | Перебування у вікні підтримки |
Перший кейс — причина, з якої існує другий розділ цієї сторінки. AngularJS, випущений 2010 року, був одним із найпопулярніших фронтенд-фреймворків у світі, коли Google оголосив його наступника на конференції ng-europe в Парижі в жовтні 2014 року. Angular 2 зберіг назву й дуже мало іншого — нова модель компонентів, новий синтаксис шаблонів, а з 2015 року й TypeScript, — і на момент анонсу не мав жодного шляху оновлення. Реакція була люта, і наступні два роки команда будувала цей шлях: ngUpgrade, що дозволяє обом фреймворкам працювати в одному застосунку, поки його переносять частинами. Angular 2.0 вийшов 14 вересня 2016 року. AngularJS увійшов у довгострокову підтримку в липні 2018 року, отримав її продовження на пів року під час пандемії й втратив 31 грудня 2021 року; його останній реліз, 1.8.3, називається «ultimate-farewell». Кожна автоматична міграція, яку Angular випустив відтоді, — почасти відповідь на 2014 рік.
Третій і четвертий кейси — та сама історія, розказана двічі. NgModules з’явилися в серпні 2016 року, у п’ятому реліз-кандидаті, за п’ять тижнів до 2.0, — здебільшого тому, що компілятору був потрібен контекст, щоб знати, які компоненти дозволено використовувати в шаблоні. Вісім років вони були поняттям, яке новачкам давалося найважче, і частиною кожного туторіала, де найімовірніше була помилка. Прибрав їх новий рушій рендерингу. Ivy, типовий з v9 у лютому 2020 року, компілює кожен компонент з усім, що той має знати про себе, тож компонент може сам перелічити свої імпорти. Standalone-компоненти стали стабільними у v15, а типовими — у v19, у листопаді 2024 року. Сама заміна рушія мала власну ціну: бібліотеки, скомпільовані під старий рушій, View Engine, працювали через компілятор сумісності, доки v16 не прибрав його в травні 2023 року з прямим попередженням у журналі змін: «бібліотеки для Angular View Engine більше не працюватимуть». Застосунок не може рухатися швидше за свою найповільнішу залежність, і деякі команди виявили, що їхню вже ніхто не підтримує.
Де він вироджується
Репутація Angular як важкого стосується переважно перших двох тижнів. Навантаження понять справді зсунуте на початок — впровадження залежностей, декоратори, сигнали, RxJS, виявлення змін, — і розробник, що працював лише з React, буде повільнішим два тижні. Купує це п’ятий рік, схожий на перший. Коли кодова база на Angular таки вироджується, рідко підводить механізм фреймворку; це старша колонка таблиці, що живе далі, або можливість, використана всупереч своїй природі.
- Підписки, які ніколи не завершують, тримають живими знищені компоненти і їхній DOM.
- Виклики функцій у шаблонах виконуються на кожній перевірці, а не при зміні даних.
OnPushзі входами, зміненими на місці: компонент не оновлюється й виглядає випадково зламаним.- Effect-и, що задають сигнали, — це
computedіз вбудованою миттю незгоди. - Вкладені підписки замість
switchMapповертають ті перегони, які оператор і мав прибрати. - Стан одного екрана в кореневому сервісі переживає навігацію й протікає між відвідуваннями.
bypassSecurityTrust…на вмісті, що прийшов від користувачів.- Новий код на NgModules і
*ngIf— це предмет наступної міграції. - Версія поза вікном підтримки, де наступний бюлетень безпеки не матиме патча.
Чесна межа — у самій засаді фреймворку. Angular вирішує за вас, і це перевага лише доти, доки його рішення пасують вашій задачі. Переважно статичний контентний сайт платить за рантайм повного фреймворку, який йому не потрібен; невелика команда, що хоче щороку пробувати нову бібліотеку стану чи роутер, боротиметься з фреймворком, а не користуватиметься ним. А однорідність ріже в обидва боки: кожен застосунок на Angular успадковує той самий графік міграцій, хай є в команди на це час у цьому кварталі чи ні.
Практична перевірка — дві команди. ng version каже, на якому рядку таблиці релізів ви перебуваєте і чи ви у вікні підтримки. ng update показує, що на вас чекає, і запускає міграції, — а робити це на кожній мажорній версії, а не на кожній третій, — це різниця між одним днем і цілим проєктом.
Коли це застосовувати
Застосовуйте, коли
- Велика організація з кількома командами, якій вигідно мати одну відповідь на питання.
- Довгоживучий продукт, де міграції між мажорними версіями коштують реальних грошей.
- Складні форми й узгоджені асинхронні потоки — найсильніша територія фреймворку.
- Команда хоче TypeScript і впровадження залежностей як даність, а не як вибір.
Уникайте, коли
- Малий проєкт чи прототип, де навантаження понять сплачується наперед і не окупається.
- Команда, яка хоче зібрати власний стек, — вона боротиметься з фреймворком, а не користуватиметься ним.
- Переважно статичний контентний сайт, де рантайм повного фреймворку не дає нічого.
- Ніхто не відповідатиме за оновлення — версія, що відстала, за два роки втрачає патчі безпеки.
Джерела й метод
На чому стоїть ця стаття
- 9 джерел
- 1 задокументований збій
- Перевірено 13 жовтня 2026 р.
Практики й походження термінів
усі будівельні блоки, версія стабілізації і таблиця підтримки- ДокументаціяVersioning and releases (відкривається в новій вкладці)angular.dev
- ДокументаціяRoadmap (відкривається в новій вкладці)angular.dev
- ДокументаціяSignals — Overview (відкривається в новій вкладці)angular.dev
- ДокументаціяhttpResource (відкривається в новій вкладці)angular.dev
- Документаціяangular/angular — CHANGELOG (відкривається в новій вкладці)GitHub
AngularJS і переписування
кейси AngularJS у «П’ять кейсів і те, чого в кожному бракувало»Збої, на яких вчиться стаття
CVE-2025-66035, останній із п’яти кейсівДослідження з Claude. Пошук і звірку першоджерел зроблено з Claude (Anthropic). Відбір, текст і перевірку фактів — редакція Anatomy of IT Product.
Було корисно?
Поділіться з тим, хто працює над тією ж задачею.