Типизация редакса

Posted on February 11, 2020

На одном из собесов дали задачку починить простенькое react-приложение с самописным flux-велосипедом. Вот кусок кода (комментарии мои):


На что пришло письмо с комментариями:



Ну тут понятно с последним комментарием никак нельзя согласиться. Сборка редьюсеров это никак не код библиотеки общего назначения, это код ИСПОЛЬЗОВАНИЯ библиотеки общего назначения, но это ладно, я готов с этим жить. Но вот проверки в рантайме… Не, я конечно промолчал и на следующий этап кастинга меня позвали, но все таки. В интернете опять кто то неправ… В том смысле что у меня у самого есть такой же код, я не готов спорить на эту тему. Но вот по поводу того что в тайпскрипте нельзя построить систему типов которая будет пресекать и бдить - я не согласен.

Вот код (рекомендую открыть его здесь )

type Handler = (state: State, action: Action) => State;

interface Handlers {
    setRole: Handler;
    someAction: Handler;
}

interface State {

}

const handlers: Handlers = {
    setRole : (state:State, action:Action) => Object.assign({}, state, { role: action.value })
   ,someAction : (state:State, action:Action) => Object.assign({}, state)
}

const reducer = (state:State, action:Action) => handlers[action.type](state, action)

interface Action {
    type: keyof Handlers
    value: any
}

reducer({}, { type: "setRole", value: "admin" });
reducer({}, { type: "badAction", value: "admin" });

Видно что компилятор сразу бросает ошибку на “badAction”:

Как это работает? Если хотим добавить новый редьюсер - добавляем сначала строку вида имя_редьюсера: Handler в интерфейс Handlers и после этого послушно следуем ругани компилятора. Он заругается на то что Property 'имя_редьюсера' is missing in type ... и не успокоится пока мы не добавим новый редьюсер:



Если мы попытаемся дернуть несуществующий экшин то ругаться компилятор будет вот так:



Если мы удалим запись из интерфейса Handlers но не удалим хандлер из const handlers - получим несоответствие типов. То же самое если сделаем наоборот - удалим из const handlers но не удалим из интерфейса.

Единственный сценарий который не отслеживается - это когда все у нас хорошо и красиво прописано но нигде в коде не используется.

Да, это не так удобно как динамичное создание редьюсеров или их merge, не спорю, но если экшинов до 50 - жить можно вполне. Сами хандлеры не обязательно прописывать в одном файле, можно ипортировать. В общем на определенных масштабах вполне себе можно жить и типобезопасно и относительно удобно.

А идет все это зло с примеров от производителя:



Мораль - читая доки иногда стоит и мозг включать.