
StackOverflow - потрясающий ресурс, каждый разработчик использует его каждый день. Более того, это может мотивировать узнавать что-то новое. Недавно я обнаружил вопрос: Значение сигнатуры типа возвращаемого значения метода createAction NgRx. Это вызвало у меня интерес, так как я довольно долго пользовался создателями экшенов, но никогда не стремился понять, как они на самом деле работают.
Те, кто работал с NgRx до версии 8, использовали для создания действий следующим образом:

Все мы помним, какое количество шаблонов было необходимо для поддержки наших действий и редукторов. С NgRx 8 стало намного проще:

Вместо того, чтобы иметь перечисление и класс для каждого типа действия, теперь нам нужно вызвать одну функцию createAction. Алекс Окрушко написал отличную статью о преимуществах создателей новых экшенов.
Итак, как они работают?
Во-первых, давайте посмотрим, что дает нам TypeScript при наведении курсора на действие logout:

Наш логин имеет тип ActionCreator<T,() => TypedAction<T>>. Первый параметр - это общий параметр T, в нашем случае это «[Auth] Logout». Вторая - функция, возвращающая TypedAction<T>. TypedAction расширяет действие, добавляя поле readonly type:

Теперь посмотрим на реализацию функции createAction:

Мы передаем type (в нашем случае «[Auth] Logout») и возвращаем функцию Creator - () => ({type: '[Auth] Logout'}). В строке 7 мы вызываем функцию defineType с типом и нашим создателем. defineType возвращает переданную функцию Creator и добавляет к ней новый тип свойства. Итак, у нас есть функция со свойством типа, которая возвращает объект со свойством типа 😵😕.
Выполнив этот трюк, мы можем вызвать logout.type и logout().type, и оба они вернут «[Auth] Logout».
Давайте посмотрим, что делают наши новые редукторы:

Вот реализация функции on:

Сначала он извлекает функцию редуктора, которая является последним аргументом (строка 2), получает тип нашего ActionCreator (строка 4) (здесь используется магия defineType) и возвращает объект с редукторами и соответствующими типами действий (строка 7). < br /> Позже, в функции createReducers:

Редукторы и действия, которые мы получаем из on функций (строка 3), встроены в карту типа действия и редуктора (строка 5). Возвращается новая функция редуктора (строка 7). Если отправленное действие находится на карте, то он выполняет связанный редуктор, в противном случае возвращается исходное состояние.
Резюме
Сначала мы определяем создателя действия:
export const login = createAction(
'[Login Page] Login',
props<{payload: {username: string; password: string;}}>(),
)
Затем мы определяем редуктор, он выполняет ons функций и внутренне строит карту типов действий и функций редуктора:
export const reducer = createReducer(
initialState,
on(AuthActions.login, (state, {username}) =>
({...state, user: username}))
);
Затем мы вызываем наш компонент или сервис:
this.store.dispatch(AuthActions.logout())
Выполняется функция создания действия AuthActions.logout(), и мы получаем TypedAction обратно со свойством type, равным «[Страница входа] Вход».
Затем reducer просматривает свою карту и пытается найти функцию reducer для данного типа. Когда редуктор найден, он выполняется, в противном случае возвращается объект состояния.