0

I was really happy with my solution here https://stackoverflow.com/a/75592058/1075247, it meant I could have a generic Meta Action in my redux application, that was easy to extend:

export interface Action<T = any> {
  type: T
}

export interface AnyAction extends Action {
  // Allows any extra properties to be defined in an action.
  [extraProps: string]: any
}

// no meta specified
interface BaseMetaAction extends AnyAction {};

export interface QueuedAction extends BaseMetaAction {
  meta: {
    queueName: string;
    overwrite: boolean;
  }
}

export interface BroadcastAction extends BaseMetaAction {
  meta: {
    channelName: string;
  }
}

export type MetaAction<T extends BaseMetaAction = AnyAction> = T & (QueuedAction | BroadcastAction);

But I have hit an unexpected snag.

I have this code to add /remove a channelName:

const wrapBroadcast = (action: AnyAction, channelName = 'DEFAULT_CHANNEL'): MetaAction<BroadcastAction> => ({
  ...action,
  meta: { ...action?.meta, channelName },
});

const unwrapBroadcast = (action: MetaAction<BroadcastAction>) => {
  if (!action.meta) return action;

  const { channelName, ...rest } = action.meta; 
  const unwrappedAction = { ...action, meta: rest };
  return unwrappedAction;
}

This worked fine before I tried to use it with some code that had a specified action type it returned, it looked like this:

type FloopThePigType = (pigId: string) => {
  type: 'CARD_ACTION:FLOOP:PIG';
  payload: { id: string };
}

// want to broadcast these - this errors
const floopThePig: FloopThePigType = (pigId) => wrapBroadcast({
  type: 'CARD_ACTION:FLOOP:PIG',
  payload: { id: pigId },
});

// dummy function
const updateLocal = (pigId: string) => {console.log(pigId)};

// don't broadcast these
const floopThePigLocal: FloopThePigType = (pigId) => {
  updateLocal(pigId);
  return {
    type: 'CARD_ACTION:FLOOP:PIG',
    payload: { id: pigId },
  };
};

Here the playground link.

But now typescript is flipping out :

Type 'MetaAction' is not assignable to type '{ type: "CARD_ACTION:FLOOP:PIG"; payload: { id: string; }; }'. Property 'payload' is missing in type 'BroadcastAction' but required in type '{ type: "CARD_ACTION:FLOOP:PIG"; payload: { id: string; }; }'

It looks like BroadcastAction wasn't are I might have wanted a payload, despite ultimately inheriting from AnyAction?

Is there a well defined pattern to this kind of passing/building actions I can follow? Or do I need a specific solution to my problem (if so I may need to give more details when I'm at work)?

AncientSwordRage
  • 7,086
  • 19
  • 90
  • 173

0 Answers0