My current project involves creating a redux-like library using TypeScript. Here is an example of the basic action structure:
interface ActionBase {
type: string;
payload: any;
}
To customize actions for different types, I extend the base interface. For instance, for a button-click event, the setup would look like this:
interface ButtonClickAction extends ActionBase {
type: 'BUTTON_CLICK';
payload: {
// Add metadata here
};
}
In addition to defining these interfaces, I am also implementing helper functions:
function isInstanceOfButtonClick(action: ActionBase ): action is ButtonClickAction {
return action.type === 'BUTTON_CLICK';
}
function buildButtonClickAction(payload): ButtonClickAction {
return {
type: 'BUTTON_CLICK',
payload,
};
}
The issue arises when dealing with multiple action types - around 20 in total. Is there a more efficient way to handle this? Each action requires:
- The specific type string (
"BUTTON_CLICK"
) - The payload type
- The action type itself (
ButtonClickAction
) - A builder function (
buildButtonClickAction
) - An instance check function (
isInstanceOfButtonClick
)
While it's possible to address items 1, 4, and 5 using classes or functions, I haven't found a streamlined approach for items 2 and 3. Currently, each action follows a similar pattern as shown below:
const KEY = 'BUTTON_CLICK';
namespace ButtonClick {
export type Payload = {...}
export interface Action extends ActionBase {
type: typeof KEY;
payload: Payload;
}
}
let ButtonClick = makeActionValues<typeof KEY, ButtonClick.Payload, ButtonClick.Action>(KEY)
export default ButtonClick;
Is there a more elegant solution to tackle this challenge?