TypeScript Memento Design Pattern

Ibrahim sengun
2 min readJan 25, 2024

--

What is memento design pattern?

The memento design pattern is a behavioral design pattern that provides the ability to save and restore an object’s state.

There are several terminologies in the memento design pattern. These are:

  • Originator: It’s the class that can produce snapshots or restore.
  • Memento: It’s a placeholder for snapshots of the originator.
  • Caretaker: It decides when or where to use snapshots.
  • Client: This refers to the application or function that communicates with the system.

When should the memento design pattern be used?

The memento design pattern can be used when there is a need for history-based operations, such as storage or restoration. It can also be employed when direct access to an object’s setters and getters violates the code design and encapsulation.

How to implement memento design pattern in TypeScript

Let’s apply the Memento design pattern to TypeScript. First, let’s imagine a scenario where we are designing a text editor application and decide to add a history feature. Initially, we design a system where, whenever there is an action in the application, it saves the state and stores it in 3rd-party objects. Upon request, the system retrieves the latest state for the client.

However, this mechanism produces a few errors when the state that we want to save and restore has inaccessible fields, like private ones. To solve this problem, if we were to change the state fields or modify them, we would compromise the system and act against the SOLID principles.

To address our predicaments, we decide to employ the Memento design pattern. With it, to solve the access problem, we delegate the copying and restoring of objects to their originator. The originator stores the copies in the Memento objects, which only the originator has access to. With a caretaker, we can decide the time of the restoration.

Memento design pattern diagram

Memento design pattern diagram

Memento design pattern code

// Memento
class TextMemento {
private state: string;

constructor(state: string) {
this.state = state;
}

getState(): string {
return this.state;
}
}

// Originator
class TextEditor {
private content: string;

constructor() {
this.content = '';
}

getContent(): string {
return this.content;
}

setContent(content: string): void {
this.content = content;
}

createMemento(): TextMemento {
return new TextMemento(this.content);
}

restoreFromMemento(memento: TextMemento): void {
this.content = memento.getState();
}
}

// Caretaker
class Past {
private mementos: TextMemento[] = [];

addMemento(memento: TextMemento): void {
this.mementos.push(memento);
}

getMemento(index: number): TextMemento {
return this.mementos[index];
}
}

// Client
const editor = new TextEditor();
const past = new Past();

past.addMemento(editor.createMemento());

editor.setContent("Hello, ");
past.addMemento(editor.createMemento());

editor.setContent("World!");
past.addMemento(editor.createMemento());

// undo
editor.restoreFromMemento(past.getMemento(1));
// Output: Hello,
console.log(editor.getContent());

// Redo
editor.restoreFromMemento(past.getMemento(2));
// Output: Hello, World!
console.log(editor.getContent());

--

--