Код Senior Объединения и сужение обновлено

Конечный автомат платежа с типами переходов

Условие

Платёж проходит состояния: pending → authorized → captured → refunded; из pending и authorized можно уйти в cancelled; из pending в failed.

Опиши:

  • PaymentState как union по полю status, где у authorized есть authCode: string, у captured и refunded есть capturedAmount: number, у failed есть reason: string;
  • PaymentEvent: authorize { authCode }, capture { amount }, refund, cancel, fail { reason };
  • transition(state, event): возвращает { ok: true; state } или { ok: false; error } с текстом cannot <event> in <status>. Захват суммы <= 0 даёт invalid amount.

replay(events) применяет события к { status: 'pending' }, останавливаясь на первой ошибке, и возвращает итоговое состояние или ошибку.

Примеры

replay([{"type":"authorize","authCode":"A1"}, {"type":"capture","amount":500}]) // {"ok":true,"state":{"status":"captured","authCode":"A1","capturedAmount":500}}
replay([{"type":"authorize","authCode":"A1"}, {"type":"capture","amount":500}, {"type":"refund"}]) // {"ok":true,"state":{"status":"refunded","capturedAmount":500}}
replay([{"type":"capture","amount":100}]) // {"ok":false,"error":"cannot capture in pending"}

Как подойти

Подсказки: 2
  1. Сначала switch по событию, внутри проверка статуса: после state.status !== "authorized" TS знает, что у состояния есть authCode.
  2. Если switch по всем вариантам события возвращает значение, TS не потребует return после него.

Решите в тренажёре

Редактор с автотестами прямо в браузере. Можно решить спокойно, вслух или под таймером, как на собесе.