Що таке циклічні залежності, де вони мешкають, та як їх вирішити
Інтродукція
В цьому дописі я хочу розповісти про те, що таке циклічні залежності, як їх знаходити та виправляти. Нещодавно мені трапилася така помилка, й мені довелося витратити щонайменше 1.5 години на її вирішення, так як вона не має очевидних логів та її не може попередити IDE.
Тож, що це таке
Уявіть, що файл A імпортує файл Б, а файл Б в свою чергу використовує якісь дані з файлу А. Це може здаватися досить сюреалістичною ситуацією, але вона може нерідко траплятися на великих проєктах, де багато модулів
Уявімо, що в нас є 3 файли: index.ts, a.ts, b.ts. Ми на нашому невеликому проєкті використовуємо ESM (EcmaScript Modules). Ви також можете запустити цей приклад в sandbox



Гортайте вбік, щоб подивитися всі зображення
Що тут станеться?

Як ми можемо побачити, в нас виникла помилка Cannot read properties of undefined. Досить незвично, правда? Вона зачасту виникає, коли ми намагаємося читати властивості з чогось, що є undefined. На кшталт:
const obj1 = undefined; const someProperty = obj1.myProperty
В цьому випадку ми отримуємо одну й ту саму помилку. Але стоп, як таке може бути? Ми ж чітко бачимо властивість serviceA, що ж тоді не так? Навіть ваш редактор коду, скоріш за все, не підкаже, в чому полягає помилка. А справа полягає в тому, що ми викликаємо файли приблизно таким чином:
index.tsa.tsb.tsa.ts
Тут компілятор думає так:
- А підтягни ка мені файл
a.ts. - Ого, тут в нас є й інший імпорт, відкладемо код нижче на потім. Йдемо до файлу
b.ts - В нас тут є ще один імпорт від файлу
a.ts, але ми такого не знаємо! Тоді призначимо значенняundefined - Експортуємо нову константу
aName, але ж нашserviceAмає значенняundefined! Викидаю помилку, що не можу прочитати властивість наundefined.
Як можна побачити, кроки 2 та 4 повторюються, й насправді можуть повторюватися до нескінченності, це й є циклічна залежність. Наша консоль навіть повністю не відображає логу, й в цьому і є велика проблема
Рішень до подібних циклічних залежностей є декілька, але вони не завжди з найпростіших:
- Можемо перенести константу
serviceAдо файлуb.ts - Можемо перенести константу
aNameдо файлуa.ts
Але суть більшості таких рішень, що ми маємо групувати контент за змістом, і не розпорошувати змінні, функції то тут, то там. Це є ключовим моментом
Сподіваюся я досить зрозуміло пояснив тему, й це врятує кому-небудь годинку-іншу часу :)
Слава Україні!!!
3 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарів