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)?