使用打字稿简化 redux 操作的样板代码

Simplify boilerplate code for redux actions with typescript

每当我们需要向我们的 react/redux 应用程序添加新操作时,我们都会复制大量样板代码,我需要一个助手来尝试加快这个过程,虽然这是一个简单的例子,这基本上就是我们需要自动化的全部内容。

我们创建一个 Action 接口,Payload 接口,action payload 需要以某种方式导出,还有“action”函数。


interface Payload {
  something: {
    [key: string]: boolean;
  }
}
export interface Action {
  type: 'UniqueRequestKey';
  payload: Payload
}

export const someAction = (payload: Payload): Action => ({
  type: 'UniqueRequestKey',
  payload
});

以上是我们目前正在做的事情,但我觉得辅助方法可以使它变得更简单,因为它有很多重复的代码,我们一遍又一遍地这样做。

我想要像下面这样简单的东西,根本不需要精确!

const [someAction, Action??] = createAction<'UniqueRequestKey', {
  something: {
    [key: string]: boolean;
  }
}>();

我知道以上内容不正确,但如果有人能引导我朝着正确的方向前进,那就太好了,我尝试了以下方法,但显然是错误的

type Combine<T, P> = {
  type: T,
  payload: P
};
function createAction<T,P>(): [(payload: P):Combine<T,P> => {}, type: T] {
  return [(payload: P): Combine<T,P> => ({
    type,
    payload
  }), type];
}

类似

const [someAction, Action] = createAction<'UniqueRequestKey', {
  something: {
    [key: string]: boolean;
  }
}>();

无法工作,因为类型不是可以在运行时创建的东西(它们只是 compile-time 概念)。 但是,你可以从他们那里得到类型定义。

想象一个像这样的简单辅助函数:

function createAction<Type extends string, Payload>(type: Type, payload: Payload) {
  return { type, payload }
}

可用于创建您自己的应用的操作:

export const someAction = (payload: {
  something: {
    [key: string]: boolean;
  }
}) => createAction('UniqueRequestKey', payload)

你可以用

提取类型
type SomeActionType = ReturnType<typeof someAction>

计算结果为

{
    type: "UniqueRequestKey";
    payload: {
        something: {
            [key: string]: boolean;
        };
    };
}

现在,如果您确实有很多操作,您可能会考虑将它们全部放在一个大对象中,

const actions = {
  someAction: (payload: {
    something: {
      [key: string]: boolean;
    }
  }) => createAction('UniqueRequestKey', payload),
  someOtherAction: (payload: {
    fooBar: number
  }) => createAction('BlaBla', payload),
}

您可以使用它来提取所有类型,如下所示:

type ActionsCollection = typeof actions

type Actions = ReturnType<
  ActionsCollection[keyof ActionsCollection]
>

其中 Actions 是一个包含应用程序中所有可用操作的大联合。从那里,如果你需要一个特定的动作,你可以从中提取它

type SomeActionType = Extract<Action, { type: 'UniqueRequestKey' }>

一般不应该自己写那样的东西,使用官方的Redux Toolkit,不仅有createAction的功能,还有createSlice的功能,可以更进一步减少你的代码——尤其是你的 TypeScript 使用量。

一般来说,现代 Redux 不使用 switch..case reducers,ACTION_TYPES 是一个实现细节,action creators 是自动生成的,你可以使用可变的 reducer 逻辑(在 createSlice 中)并且几乎不写 TypeScript。总而言之大概是代码的1/4。

Please follow the official Redux Tutorial 使用 Redux Toolkit 学习当前的 Redux。