Использование типов Typescript, чтобы гарантировать, что все типы действий обрабатываются редуктором - PullRequest
0 голосов
/ 19 февраля 2020

Я пытался создать своего рода сопоставление с шаблоном в машинописи, особенно здесь, для создания редукторов Redux.

Я бы очень хотел иметь возможность заранее указать, что редуктор должен обрабатывать все действия определенного типа. Я попытался сделать это, создав объект, который имеет ключ по типу действия, со значениями, которые являются редукторами. Типы для этого отображения выглядят так:

export interface IReduxAction<T> {
    type: T;
}

interface IReducer<S, A> {
    (state: S, action: A): S;
}

export type IActionReducerMapping<S, A extends IReduxAction<string>> = Record<A['type'], IReducer<S, A>>;

Это делает большую часть того, что я планировал; любое отображение, созданное для данного типа действия, должно реализовывать все типы действий. Проблема в том, что, как я настроил типизацию, редукторы в отображении не могут определить точный тип их действия. Например:

interface IUser {
    id: number;
    name: string;
    age: number;
}

interface IUserState {
    [id: number]: IUser;
}

interface IAddUserAction {
    type: 'ADD_USER';
    payload: IUser;
}

interface ISetUserNameAction {
    type: 'SET_USER_NAME';
    payload: {
        id: IUser['id'];
        name: IUser['name'];
    }
}

type UserAction = IAddUserAction | ISetUserNameAction;

const mapping: IActionReducerMapping<IUserState, UserAction> = {
    // here action is only aware of the properties on UserAction
    // ideally it'd know that it has access to the properties of
    // IAddUserAction
    'ADD_USER': (state, action) => ({
        ...state,
        [action.payload.id]: action.payload,
    }),

    'SET_USER_NAME': (state, action) => ({
        ...state,
        [action.payload.id]: {
            ...state[action.payload.id],
            name: action.payload.name,
        }
    }),
};

Проблема состоит в том, что действие в каждом редукторе является только объединением типа UserAction, и поэтому, например, age не доступен. Есть ли способ настроить типизацию с таким типом шаблона, чтобы:

  1. Я мог гарантировать, что все типы действий обрабатываются, так или иначе
  2. Я могу настроить редукторы, которые знают тип действия им дан

1 Ответ

1 голос
/ 19 февраля 2020

Вы можете решить проблему с action, не имеющим правильного типа, используя настраиваемый сопоставленный тип, который сопоставляет все типы (A['type']) и использует условный тип Extract, чтобы получить правильный тип действия для название каждого типа.


export type IActionReducerMapping<S, A extends IReduxAction<string>> = {
    [K in A['type']]: IReducer<S, Extract<A, { type: K }>>
};

Playground Link

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...