Kyle Johnson
Kyle Johnson

Reputation: 961

Typescript: Returning a union based on ReturnTypes in object

My initial code is as follows, it allows me to detect the type of data based on the type when doing a switch on action:ActionType.

enum Actions {
  GET_MESSAGES,
  GET_MESSAGES_LOADED
}

//@ts-ignore
const AppActions = {
  getMessages() {
    return {
      type: Actions.GET_MESSAGES,
      data:{id: 1}
    };
  },
  getMessagesLoaded() {
    return {
      type: Actions.GET_MESSAGES_LOADED,
      data:{messages: ['asdf']}
    };
  }
};

type ActionType = ReturnType<typeof AppActions[keyof typeof AppActions]>;


const func = (action:ActionType) => {
  // @ts-ignore
  switch (action.type) {
      case Actions.GET_MESSAGES:
          console.log(action.data.id) //Should pass
          break
      case Actions.GET_MESSAGES_LOADED:
        console.log(action.data.messages) //Should pass
          break;
      case Actions.GET_MESSAGES_ERROR: // Should throw typescript error
      // default:
      //   break;
  }
};

What I'd like to know is can I create the ActionType union dynamically by mapping over keys of AppActions?

Closest Answer so far

@Elias's answer so far of type ActionType = ReturnType<typeof AppActions[keyof typeof AppActions]>; cuts out most of the bloat here.

The above works perfectly so long as each function in AppActions has a specified return type, without this the type of data cannot be detected however it does detect correctly Actions.GET_MESSAGES_ERROR is an invalid action.type.

Upvotes: 3

Views: 56

Answers (1)

Elias
Elias

Reputation: 4141

This answer works in extracting the type, but type guards fail to resolve and reveal the underlying type!

enter image description here

enter image description here

Anser

type ActionType = ReturnType<typeof AppActions[keyof typeof AppActions]>;

You don't even need to specify the return type of the functions:

const AppActions = {
    getMessages() {
        return {
            messages: ["asdf"],
        };
    },
    getMessagesLoaded() {
        return {
            loadedMessages: [1],
        }
    },
};

Upvotes: 1

Related Questions