How do I overload a function with union type instances

Viewed 32

I have this payload type

type DriverReducerPayloadType = User | Direction | moment.Moment | boolean

This action type

type DriverReducerActionType =
  | 'SET_DIRECTION'
  | 'SET_CURRENT_USER'
  | 'SET_IS_LOADING'
  | 'SET_SELECTED_DATE'

This action interface

interface IDriverReducerAction {
  type: DriverReducerActionType
  payload: { data: DriverReducerPayloadType }
}

And this action creator function.

export function driverReducerAction(
  type: DriverReducerActionType,
  payload: DriverReducerPayloadType
): IDriverReducerAction {
  return { type, payload: { data: payload } }

I want to lock action types to payload types so that SET_DIRECTION accepts only a Direction type as payload, etc. How do I properly overload this? If I just write the overloads with the literals from the action type, it seems to lose its point of writing the type out. Or am I missing something?

1 Answers

Yeah, you can't do it without literals.
Here is how I would do it:

type Overload<T, P> = (type: T, payload: P) => { type: T; payload: { data: P } };

type DriverReducerActionFunc =
  & Overload<'SET_DIRECTION', Direction>
  & Overload<'SET_CURRENT_USER', User>
  & Overload<'SET_IS_LOADING', boolean>
  & Overload<'SET_SELECTED_DATE', moment.Moment>;

export const driverReducerAction: DriverReducerActionFunc = (type, payload) => {
  return { type, payload: { data: payload } };
};

If noImplicitAny is set to true:

export const driverReducerAction = <DriverReducerActionFunc>((type, payload) => {
  return { type, payload: { data: payload } };
});
Related