December 19, 2025 (8mo ago) — last updated July 12, 2026 (1mo ago)

Патерн Адаптер у TypeScript, React і Node.js

Як патерн Адаптер у TypeScript, React і Node.js з’єднує несумісні інтерфейси, модернізує колбек-API та уніфікує дані для чистішої архітектури.

← Back to blog
Cover Image for Патерн Адаптер у TypeScript, React і Node.js

Патерн Адаптер дозволяє об’єднати несумісні інтерфейси без зміни існуючого коду — у статті наведено практичні приклади на TypeScript, React і Node.js, щоб ви могли швидко модернізувати інтеграції.

Патерн Адаптер: приклади з TypeScript, React і Node.js

Коротко: Дізнайтеся, як патерн Адаптер з’єднує несумісні інтерфейси в TypeScript, React і Node.js на практичних прикладах, щоб модернізувати інтеграції й зберегти чисту архітектуру.

Вступ

Часто доводиться підключати сторонні бібліотеки або підтримувати застарілий модуль, який «не вписується» в решту системи. Патерн Адаптер вирішує цю проблему, перекладаючи інтерфейс одному в інший і дозволяючи повторно використовувати існуючий код без його змін. У цьому матеріалі наведено коротке пояснення патерну, приклади на TypeScript і React, а також адаптер для Node.js, що перетворює колбеки на Promise — все це з фокусом на практичні кроки, які можна застосувати негайно.

Чому патерн Адаптер важливий

Патерн Адаптер — структурний патерн, який обгортає несумісний об’єкт і надає інтерфейс, який очікує ваш код. Цей патерн задокументовано Gang of Four у 1994 році1. Адаптери корисні для інтеграції сторонніх API, модернізації застарілого коду та уніфікації розрізнених джерел даних.

Типові сценарії, де адаптери особливо допомагають:

  • інтеграція сторонніх API з різними форматами відповіді;
  • перетворення API на основі колбеків у Promise/async-await;
  • уніфікація кількох джерел даних в один передбачуваний інтерфейс для UI.

Використання адаптера зберігає бізнес-логіку чистою й незалежною від зовнішніх систем.

Патерн Адаптер — короткий огляд

ПоняттяОпис
ТипСтруктурний
Основна метаДозволити об’єктам з несумісними інтерфейсами працювати разом
ІдеяОбгорнути adaptee, щоб надати інтерфейс, який очікує клієнт
Вирішувана проблемаПовторне використання класів без зміни їхнього коду
Часті випадкиСторонні бібліотеки, legacy-код, кілька джерел даних

Структура та ролі

Ролі патерну:

  1. Клієнт — код, який потребує певного інтерфейсу.
  2. Цільовий інтерфейс — контракт, який очікує клієнт.
  3. Adaptee — існуючий клас або модуль із потрібною логікою, але з іншим інтерфейсом.
  4. Адаптер — реалізує цільовий інтерфейс і делегує виклики adaptee, переводячи їх за потреби.

Два поширені стилі адаптера:

  • Об’єктний адаптер (композиція): адаптер містить екземпляр adaptee.
  • Класовий адаптер (успадкування): адаптер наслідує adaptee і реалізує target — рідше в JS/TS через обмеження успадкування.

Практичний приклад: TypeScript + React

Уявіть панель керування, яка отримує профілі користувачів з двох сервісів з різними схемами відповіді. Без адаптера компоненти міститимуть умовну логіку та дубльований код. Адаптер централізує перетворення.

Несумісні форми API

// Data from UserServiceA
interface UserA {
  userId: number;
  fullName: string;
  emailAddress: string;
}

// Data from UserServiceB
interface UserB {
  id: string;
  name: string;
  contact: {
    email: string;
  };
}

Цільовий інтерфейс для додатку

interface UnifiedUser {
  id: string;
  name: string;
  email: string;
}

Адаптери на TypeScript

// Adapter for UserServiceA
function adaptUserA(userA: UserA): UnifiedUser {
  return {
    id: userA.userId.toString(),
    name: userA.fullName,
    email: userA.emailAddress,
  };
}

// Adapter for UserServiceB
function adaptUserB(userB: UserB): UnifiedUser {
  return {
    id: userB.id,
    name: userB.name,
    email: userB.contact.email,
  };
}

Централізація перетворень робить компоненти чистими й стійкими: якщо API змінює поле, змінюється тільки адаптер.

React-компонент, який споживає уніфіковані дані

interface UserProfileProps {
  user: UnifiedUser;
}

const UserProfile: React.FC<UserProfileProps> = ({ user }) => {
  return (
    <div>
      <h2>{user.name}</h2>
      <p>ID: {user.id}</p>
      <p>Email: {user.email}</p>
    </div>
  );
};

Такий компонент спирається на одну передбачувану форму, що спрощує тестування й повторне використання.

Приклад: модернізація модуля Node.js на основі колбеків

Застарілі модулі часто використовують error-first callbacks. Замість змінювати стабільний модуль, створіть адаптер, який повертає Promise і працює з async/await.3

Застарілий adaptee (не змінюйте)

// legacyFileProcessor.js
const fs = require('fs');

class LegacyFileProcessor {
  processFile(filePath, callback) {
    fs.readFile(filePath, 'utf8', (err, data) => {
      if (err) {
        return callback(err, null);
      }
      const processedContent = data.toUpperCase();
      callback(null, processedContent);
    });
  }
}

module.exports = LegacyFileProcessor;

Адаптер, що повертає Promise

// FileProcessorAdapter.js
const LegacyFileProcessor = require('./legacyFileProcessor');

class FileProcessorAdapter {
  constructor() {
    this.legacyProcessor = new LegacyFileProcessor();
  }

  processFile(filePath) {
    return new Promise((resolve, reject) => {
      this.legacyProcessor.processFile(filePath, (err, data) => {
        if (err) return reject(err);
        resolve(data);
      });
    });
  }
}

module.exports = FileProcessorAdapter;

Це нагадує util.promisify у Node.js, але з явною логікою адаптації, що полегшує тести й інструментування.3

Використання адаптера в застосунку

const FileProcessorAdapter = require('./FileProcessorAdapter');
const fileProcessor = new FileProcessorAdapter();

async function handleFileProcessing() {
  try {
    console.log('Processing file with modern async/await...');
    const content = await fileProcessor.processFile('my-file.txt');
    console.log('Processed Content:', content);
  } catch (error) {
    console.error('An error occurred:', error);
  }
}

handleFileProcessing();

Так ви зберігаєте застарілий код недоторканим і надаєте решті кодової бази сучасний інтерфейс.

Коли варто використовувати адаптер

Використовуйте адаптер, коли два компоненти не можуть спілкуватися напряму через несумісні інтерфейси.

Коли використовувати:

  • не можна змінити сторонню бібліотеку;
  • поступова міграція legacy-систем;
  • кілька джерел даних з різними форматами, які потрібно уніфікувати.

Коли не варто:

  • якщо ви контролюєте обидві сторони й невелике рефакторинг вирішить проблему — краще рефакторити;
  • якщо потрібно надати високорівневий простий інтерфейс для складної підсистеми — розгляньте Фасад.

Швидкий чекліст

СитуаціяВикористовувати адаптер?Чому
Стороння бібліотека з іншим APIТакНеможливо змінити бібліотеку
Контролюєте обидві сторони, зміни маліНіПрямий рефакторинг простіший
Потрібен спрощений інтерфейсНіФасад краще підходить
Міграція legacy систем поетапноТакОбгортка старого компонента корисна
Багато різних структур данихТакАдаптери уніфікують форму

Тестування й продуктивність

Адаптери покращують тестованість: ви можете мокати інтерфейс адаптера для ізольованих тестів і тестувати адаптер окремо, щоб перевірити логіку перетворення. Накладні витрати зазвичай мінімальні — один додатковий виклик функції — і часто менші за мережеві затримки чи запити до бази даних. JavaScript залишається найпопулярнішою мовою розробників, тому інтеграційні завдання, які вирішують адаптери, трапляються дуже часто (див. статистику)4.

Внутрішні посилання та додаткове читання


Часті запитання — скорочені відповіді

Питання: Яку проблему вирішує патерн Адаптер?

Відповідь: Він вирішує несумісність інтерфейсів, переводячи виклики клієнта в ті, які розуміє adaptee, що дозволяє повторно використовувати код без його зміни.

Питання: Як адаптер допомагає з застарілим кодом?

Відповідь: Адаптер обгортає legacy-модулі й надає сучасний інтерфейс (наприклад, Promise), дозволяючи інтегрувати стабільний код у нові частини застосунку без ризикових переробок.

Питання: Коли обрати Адаптер замість інших патернів?

Відповідь: Обирайте Адаптер, коли потрібно забезпечити сумісність між двома невідповідними інтерфейсами. Якщо ж потрібно спростити доступ до складної підсистеми, краще використати Фасад.

1.
Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994). [https://en.wikipedia.org/wiki/Design_Patterns_(book)](https://en.wikipedia.org/wiki/Design_Patterns_(book))
2.
Adapter pattern overview and examples: https://www.geeksforgeeks.org/adapter-pattern/
3.
Node.js documentation for util.promisify, приклад перетворення callback → Promise: https://nodejs.org/api/util.html#utilpromisifyoriginal
4.
Stack Overflow Developer Survey 2023: дані про популярність JavaScript та роль веб-технологій у щоденній роботі розробників. https://survey.stackoverflow.co/2023/
← Back to blog
🙋🏻‍♂️

ШІ пише код.
Ви робите його довговічним.

В епоху прискорення ШІ чистий код — це не просто хороша практика — це різниця між системами, які масштабуються, та кодовими базами, які руйнуються під власною вагою.