Стендап Сьогодні
📢
Канал в Telegram @stendap_sogodni
🦣
@stendap_sogodni@shevtsov.me в Федиверсі
15.10.2025
Міст з узагальненими типами на TypeScript
У Firebase, окрім стандартного для JavaScript пакету firebase, є також неофіційний пакет React Native Firebase. Він побудований на “рідних” інтеграціях для iOS та Android, а тому має переваги саме на мобільному пристрої.
От тільки є проблема: хоч RNFirebase майже збігається зі стандартним Firebase за API, але типи для TypeScript оголошує власні. Що з одного боку логічно, бо кожен має власну реалізацію цих типів — наприклад, і там, і там є клас CollectionReference
. А з іншого — унеможливлює написання спільного коду, що буде працювати й в браузері, і в React Native. Або чи правда унеможливлює?
(Окремим аспектом тут є те, що не так давно Firebase перейшов з класового API на функціональний. Тобто замість app.firestore().collection("path")
тепер є collection(getFirestore(app), "path")
. Що і спрощує, і ускладнює задачу.)
Отже, що я зробив? Для початку, весь шар, який звертається до Firebase, в мене прихований в клас. Методи цього класу працюють вже з простими обʼєктами. Можна було б на цьому й зупинитися, розставити всередині класу примусові типи.
Якщо трохи серйозніше ставитись, то можна тепер зробити дві версії класу. Кожна буде імпортувати відповідний пакет та мати всередині повністю сумісні типи. Це реалізація якогось там патерну, не памʼятаю якого. Але доведеться повторити купу коду. (Та й, очевидно, підтримувати в майбутньому.)
Тому знайшов ще краще рішення — оголосив інтерфейс (насправді в ньому більше й параметрів, і методів:)
interface FirebaseAPI<CollectionReference> {
collection(path: string): CollectionReference;
}
class FirebaseLayer<CollectionReference> {
constructor(api: FirebaseAPI<CollectionReference>) {}
}
export let firebaseLayer: FirebaseLayer<unknown>;
Тепер залишається окремо для мобільної та вебверсії реалізувати інтерфейс з конкретними типами та передати цю реалізацію в шар абстракції. А решта коду зовсім не цікавиться тим, які конкретні типи всередині.
Так вийшло мати на 100% покритий типами код та, можна сказати, мінімум повторення (а повторення все ж є, бо реалізації інтерфейсу майже однакові.)