Изначально задачу я сформулировал так — предоставить возможность программисту, который будет писать модуль, возможность работать с браузерным хранилищем, причём так, чтобы он не знал, с чем именно будет работать его модуль в рантайме — с sessionStorage, localStorage, IndexedDB, WebSQL или еще какой приблудой.
Для этого я решил воспользоваться паттерном Tagless Final (он же Finally Tagless Interpreters), описанным Олегом Киселёвым в серии одноимённых пейперов. Сам модуль реализован как Reader, принимающий в качестве среды некие Options<M>
, содержащие, в том числе, и поле storage
типа StorageAlgebra<M> & Monad<M>
. Таким образом, программист модуля сможет выстраивать цепочки монадических операций, а уже внешняя среда, запускающая модуль, будет знать, с чем она работает, и запускать эти цепочки на выполнение. Например, в тестовой среде можно будет использовать простой Either<L, R>
для запуска тестов синхронно; в случае использования sessionStorage/localStorage — IOEither<L, R>
, а уж если мы размахнулись на IndexedDB/WebSQL/REST/GraphQL/whatever — тогда можно и TaskEither<L, R>
применить. Код модуля при этом менять не придется, разумеется.
Но я не учёл одной простой, если не сказать «прописной», истины. Как архитектор, я настаиваю на том, чтобы работа с хранилищем происходила в redux-saga
, который сам по себе асинхронный. Так что все мои приседания не имели большого смысла, и можно было ограничиться простым localForage.
Тем не менее, ниже приведен код моего решения — чисто как умозрительное упражнение.
Ничего не понял потому что тупой, но прочитал с удовольствием