使用Typescript类型来确保所有操作类型都由reducer处理

时间:2020-02-19 11:15:06

标签: typescript redux

我试图在打字稿中创建一种模式匹配,尤其是在这里,用于创建Redux reducer。

我真的很想能够提前指定一个减速器必须处理特定类型的所有动作。我试图通过创建一个由操作类型作为键的对象来实现此目的,该对象的值是reduce。此映射的类型如下:

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,因此无法访问年龄。有没有一种方法可以设置这种类型的键入,例如:

  1. 我可以确保以一种或另一种方式处理所有动作类型
  2. 我可以设置减速器,这些减速器知道它们给出的动作类型

1 个答案:

答案 0 :(得分:1)

您可以通过使用自定义映射类型来解决action类型不正确的问题,该自定义映射类型可以映射所有类型(A['type'])并使用Extract条件类型获取每种类型名称的正确操作类型。


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

Playground Link