I'm making a function that accepts an array of Action
s, a type that only requires it to have a type
property. While writing tests for that function I made a mistake and passed the Action Creator directly instead of the result of calling it, making the test to fail. After I found the error, I realized typescript didn't complain, because BaseActionCreator
also has a type
property so for typescript they are interchangeable if I pass any of them as an argument (which it seems I don't want to happen).
Is there any particular reason for this? and, is there a way to prevent Action Creators from being accepted as arguments?
An example of what's going can be seen at: https://codesandbox.io/embed/typescript-playground-export-forked-0qjt4k?fontsize=14&hidenavigation=1&theme=dark
import { Action, createAction } from "@reduxjs/toolkit";
function myFunction(actions: Action[]) {
actions.forEach((action) => console.log(action.type));
}
const customActionCreator = createAction("CUSTOM");
myFunction([customActionCreator()]);
myFunction([customActionCreator]);
CodePudding user response:
A BaseActionCreator
(or in your case, a ActionCreatorWithoutPayload
) requires the type
property to compare itself with other action creators.
We can see it being used inside the .match
method.
actionCreator.match = (action: Action<unknown>): action is PayloadAction =>
action.type === type
This means that any ActionCreatorWithoutPayload
is also assignable to Action
since they both have the payload
and type
properties. But we essentially want to disallow ActionCreatorWithoutPayload
from being passed to the function.
We could look at what properties ActionCreatorWithoutPayload
has addtionally. Since it is a function, it has the call
property which we can "blacklist" by intersecting Action
with { call?: never }
.
function myFunction(actions: (Action & { call?: never })[]) {
actions.forEach((action) => console.log(action.type));
}
Which gives us the desired error.
myFunction([customActionCreator()]);
myFunction([customActionCreator]);
// ^^^^^^^^^^^^^^^^^^^ Type 'ActionCreatorWithoutPayload<"CUSTOM">' is
// not assignable to type '{ call?: undefined; }