TypeScript Adapter Design pattern

Ibrahim sengun
2 min readJan 3, 2024

--

What is adapter design pattern?

The Adapter design pattern is a structural design pattern. It allows incompatible interfaces to work with each other by turning one interface into an object so that those aiming to collaborate can understand the interface. An adapter is also referred to as a wrapper because it envelops the object, hiding the complexity of conversions happening between interfaces and objects. This way, the wrapped object remains unaware of the adapter.

There are several terminologies associated with the Adapter design pattern:

  • Target: It defines the requirements needed for collaboration.
  • Adapter: It handles the requirements provided by the target and wraps the adaptee objects.
  • Adaptee: It’s the object that is incompatible and inaccessible with the client, and it’s the object that is going to be converted.
  • Client: Application or object that is going to interact with the target.

When should the adapter design pattern be used?

The Adapter design pattern can be used in scenarios where there is a need to work with existing classes; however, due to their incompatible interfaces, it becomes impossible to perform the required tasks. In such situations, the Adapter design pattern can be applied by wrapping incompatible objects and converting them to the desired type.

How to implement adapter design pattern in TypeScript

Let’s try to apply the Adapter design pattern in TypeScript. Suppose we’re managing various types of APIs, each providing data in different shapes and designs. We’ve already built the infrastructure for fetching this data and presentation. However, due to the differences in the data structures, we’re facing difficulties in handling them uniformly.

If we attempt to create distinct fetching systems for each type of data, we’ll encounter increased complexity and a higher number of classes in our project. We wondered: could we convert the data into our desired format without altering our existing system? That’s why we’ve employed the Adapter design pattern, using it to create a middle layer between our data-fetching systems and data presentation. This layer serves as a converter, enabling us to handle any type of data without disrupting our system’s functionality.

Adapter desing pattern diagram

Adapter desing pattern diagram

Adapter desing pattern code

// Adaptee 
class APIData {
fetchData(): any {
return {
data: {
name: 'ibrahim',
age: 25,
social: {
email: 'ibrahim@sengun.com'
},
},
};
}
}

// Target
interface JustifiedData {
name: string;
age: number;
email: string;
}

// Adapter
class Conventer implements JustifiedData {
private apiData: APIData;

constructor(apiData: APIData) {
this.apiData = apiData;
}

get name(): string {
return this.apiData.fetchData().data.name;
}

get age(): number {
return this.apiData.fetchData().data.age;
}

get email(): string {
return this.apiData.fetchData().data.social.email;
}
}

// Client
function displayData(data: JustifiedData) {
console.log("Name: " + data.name);
console.log("Age: " + data.age);
console.log("Email: " + data.email);
}

const apiData = new APIData();
const adaptedData = new Conventer(apiData);
displayData(adaptedData);

/*
Name: ibrahim
Age: 25
Email: ibrahim@sengun.com
*/

--

--