TGViewer
Настоящий JavaScript Настоящий JavaScript @true_js · 5.89K subscribers
Post #3591 325
⁣Branded Memento: типизация приватного состояния без компромиссов

Классический паттерн Снимок (Memento) часто сводится к поверхностной инкапсуляции: TypeScript private ломается через as any или Object.keys, а runtime-доступ к состоянию остается открытым. В production — будь то state management в SPA, логирование в Node.js-сервисах или rollback в API-клиентах — это приводит к неявным мутациям и багам. Решение лежит в комбинации branded типов и WeakMap.

Branded type как физический барьер

Memento — не контейнер данных, а заглушка с уникальным символом:

declare const MementoBrand: unique symbol;
interface Memento {
readonly [MementoBrand]: void;
}


Снаружи невозможно прочитать [MementoBrand] — он просто не существует в runtime. Любая попытка as any не даст доступа к реальному состоянию, так как его там нет.

WeakMap: приватность без утечек

Реальное состояние хранится в WeakMap<Memento, State>. Ключ — сам объект Memento, который генерируется внутри класса:

const stateMap = new WeakMap<Memento, { balance: number }>();

class BankAccount {
private balance = 0;

createSnapshot(): Memento {
const memento = {} as Memento;
stateMap.set(memento, { balance: this.balance });
return memento;
}

restore(memento: Memento) {
const state = stateMap.get(memento);
if (state) this.balance = state.balance;
}
}


Сборщик мусора автоматически удаляет запись, когда снимок больше не используется. Никаких утечек.

Практический совет и типичная ошибка

Сериализовать такой Memento напрямую в JSON нельзя — WeakMap не итерируется. Решение: если нужна де/сериализация, замени WeakMap на Map<string, State> и генерируй UUID для снимка. Теряешь автогарбаж, но получаешь поддержку persistence.

*Типичная ошибка:* пытаться сделать Memento как простой объект с полями. Даже readonly в TS не защитит от Object.assign или деструктуризации в модульных тестах.

Вывод: Branded types в паре с WeakMap превращают TypeScript из системы типов в инструмент настоящей инкапсуляции, где приватность гарантируется на уровне исполнения, а не только компиляции.
More from @true_js
  1. Oct 3, 2026Post #3963
  2. Oct 2, 2026😅 Айтишник отправил в одну компанию три одинаковых резюме и только одно дошло до финала О…
  3. Oct 2, 2026Post #3961
  4. Oct 2, 2026🤣 Правильно расставленные приоритеты в моей жизни би лайк: 💥 xCode Journal
  5. Oct 1, 2026🤯 Люди взбунтовались против «пыточной для ИИ» На GitHub заметили открытый проект AI Tortu…
  6. Oct 1, 2026День в Заонежье начинается ещё в дороге. Мы встретим вас в аэропорту или на вокзале. Дальш…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →