In the process of developing a wrapper function, I am passing a refs
property into a send
function. The Event type used to construct my state machine is defined as an intersection between a base interface { refs: NodeRefs }
and a union of possible event objects like
{ type: "EVENT_1" } | { type: "EVENT_2", context: MyContextType }
.
The objective of the wrapper function (referred to as useMachine
in the example code) is to enhance the send
function by expecting an event object where the refs
key is omitted. However, utilizing Omit
in this scenario leads to an error when using the send function with non-shared properties from the union type, leaving me uncertain about resolving this issue.
enum States {
Unchecked = "UNCHECKED",
Checked = "CHECKED",
Mixed = "MIXED"
}
enum Events {
Toggle = "TOGGLE",
Set = "SET",
UpdateContext = "UPDATE_CONTEXT"
}
// The events for the state machine will be represented as a union type named TEvent. All events
// must include a `refs` property, yet we can eliminate the need to explicitly pass refs
// thanks to the useMachine hook below
interface EventBase {
refs: NodeRefs;
}
type TEvent = EventBase &
(
| { type: Events.Toggle }
| {
type: Events.Set;
state: States;
}
| {
type: Events.UpdateContext;
context: Partial<Context>;
}
);
function useMachine(stateMachine: SomeStateMachine, refs: ReactRefs) {
let [currentState, setCurrentState] = useState(stateMachine.initialState);
/* ... */
// It is intended to exclude the refs property from our event here because identical values are always sent in each event. However, this approach triggers an error
// in our send function below.
function send(event: Omit<TEvent, "refs">) {
let nodes = Object.keys(refs).reduce(nodeReducer);
service.send({ ...event, refs: nodes });
}
return [currentState, send];
}
function MyComponent({ disabled }) {
let inputRef = useRef<HTMLInputElement | null>(null);
let [currentState, send] = useMachine(myStateMachine, { input: inputRef });
useEffect(() => {
send({
type: Events.UpdateContext,
// Error: Object literal may only specify known properties, and 'context'
// does not exist in type 'Pick<TEvent, "type">'.
context: { disabled }
});
}, [disabled]);
/* ... */
}
type NodeRefs = {
input: HTMLInputElement | null;
};
type ReactRefs = {
[K in keyof NodeRefs]: React.RefObject<NodeRefs[K]>;
};