Сужение типа действия TypeScript при использовании createAsyncAction typesafe-actions - PullRequest
0 голосов
/ 30 января 2019

При использовании typesafe-actions мы можем создать действие без использования констант в нашем приложении, например так:

export const toggle = createStandardAction('todos/TOGGLE')<string>();

И затем в редукторе мы сделаем что-то подобное, чтобы сузитьвниз по типу в каждом case блоке:

import { ActionType, getType } from 'typesafe-actions';
import * as todos from './actions';

type TodosAction = ActionType<typeof todos>;

export default (state: Todo[] = [], action: TodosAction) => {
    switch (action.type) {
        case getType(todos.add):
            // Below action type is narrowed to: { type: "todos/ADD"; payload: Todo; }
            return [...state, action.payload];

        ...

        default:
            return state;
}

Однако в моем случае я использую async-flow, поэтому мои действия выглядят так:

import { ActionType, createAsyncAction } from 'typesafe-actions';

import {
    getAsyncFetchActionConstants,
    getAsyncCreateActionConstants,
    getAsyncDeleteActionConstants,
} from '../utils/asyncActions.utils';

const BASE_ACTION = 'AUTH';

export const fetchAuth = createAsyncAction(
    ...getAsyncFetchActionConstants(BASE_ACTION))<void, AuthState, Error>();

export const createAuth = createAsyncAction(
    ...getAsyncCreateActionConstants(BASE_ACTION))<void, AuthState, Error>();

export const deleteAuth = createAsyncAction(
    ...getAsyncDeleteActionConstants(BASE_ACTION))<void, AuthState, Error>();

export type AuthRequestActions
    = ActionType<typeof fetchAuth.request> | ActionType<typeof createAuth.request> | ActionType<typeof deleteAuth.request>;

export type AuthSuccessActions
    = ActionType<typeof fetchAuth.success> | ActionType<typeof createAuth.success> | ActionType<typeof deleteAuth.success>;

export type AuthErrorActions
    = ActionType<typeof fetchAuth.failure> | ActionType<typeof createAuth.failure> | ActionType<typeof deleteAuth.failure>;

export type AuthActions = AuthRequestActions | AuthSuccessActions | AuthErrorActions;

getAsync[Fetch|Create|Delete]ActionConstants - это просто вспомогательные функции, которые возвращают массив из 3 строк:

export function getAsyncActionConstants(actionName, entityName): [string, string, string] {
    return [
        `${ actionName }_${ entityName }_${ ASYNC_REQUEST }`,
        `${ actionName }_${ entityName }_${ ASYNC_SUCCESS }`,
        `${ actionName }_${ entityName }_${ ASYNC_FAILURE }`,
    ];
}

И в моем редукторе у меня есть:

import { getType } from 'typesafe-actions';

import { AUTH_INITIAL_STATE } from './auth.constants';
import { fetchAuth, createAuth, deleteAuth, AuthActions, AuthActions } from './auth.actions';

export function authReducer(state: AuthState = AUTH_INITIAL_STATE, action: AuthActions) {
    switch (action.type) {

        case getType(fetchAuth.success):
            // TS ERROR: Property 'payload' does not exist on type 'AuthActions'. Property 'payload' does not exist on type 'EmptyAction<string>'.
            return action.payload;

        ...

        default:
            return state;
    }
}

Я бы хотелчтобы можно было работать как в первом (не асинхронном) примере без приведения.

Кроме того, было бы замечательно, если бы кто-то мог предложить, как создать type AuthActions без такого большого количества шаблонов.

...