Home > OS >  Simplify boilerplate code for redux actions with typescript
Simplify boilerplate code for redux actions with typescript

Time:03-24

Whenever we need to add a new action to our react/redux application, we copy a lot of boilerplate code, I'd like a helper to try and speed up this process, whilst this is a simple example, it's basically all we'll need to automate.

We create an Action interface, Payload interface, the action payload will need to be exported somehow, and the "action" function as well.


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

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

The above is what we're currently doing, but i feel like a helper method could make this a lot simpler as it's a lot of repetitive code, we're doing this over and over and over again.

I'd like something simple like the following, doesn't have to be exact at all!

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

I know the above isn't correct, but if someone could steer me in the right direction that would be great, I've attempted this with the following but it clearly is wrong

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];
}

CodePudding user response:

Something like

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

cannot work, because types aren't something that can be created at runtime (they are only compile-time concepts). But, you can get the type definition from them.

Imagine a simple helper function like this:

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

which can be used to create your own app's actions:

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

which you can extract the type with

type SomeActionType = ReturnType<typeof someAction>

which evaluate to

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

Now, if you do have a lot of actions, you may want to consider to just put them all in one big object,

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

which you can use to extract all the types like so:

type ActionsCollection = typeof actions

type Actions = ReturnType<
  ActionsCollection[keyof ActionsCollection]
>

where Actions is a big union with all the available actions you have in the application. From there, if you need one particular action, you could just extract it from it

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