DEV Community

Cover image for Typescript: Create a Union from a Type
Matías Hernández Arellano
Matías Hernández Arellano

Posted on • Originally published at matiashernandez.dev

2 1

Typescript: Create a Union from a Type

Originally written at https://matiashernandez.dev

How can you transform a Typescript Type into a Union Type? And most important, Why would you want to do that?

A few days ago, I encountered myself refactoring a code from using multiple useState that handled related states into a useReducer.

My rule of thumb is: If you have 3 related useState, you should move that to be a useReducer

The issue came because the state was a vast set of properties, and I wanted to cut back the time of refactoring, so I want to reuse some of the previous code.

So, I decided that I needed to create the actions for this new reducer based on the names of the State, so basically created a union type based on the State type.

So, the use case:

  • I had a type to represent a State
  • I want to create a list of actions based on that State

The goal was to do something like the following snippet.

type State = {
  searchKeyWords: string;
  isSlidingPanelOpen: boolean;
  selectedJobDocumentId: number;
}

// I want to create this

type Actions = {
  type: 'searchKeyWords',
  payload: string
} | {
  type: 'isSlidingPanelOpen',
  payload: boolean
} | {
  type: 'selectedJobDocumentId',
  payload: number
}

/// So it can be used like this
function reducer(state: State, action: Actions) {
  switch(action.type){
    case 'searchKeyWords':
      return {
        ...state,
        searchKeyWords: action.payload
      }
    case 'isSlidingPanelOpen':
      return {
          ...state,
          isSlidingPanelOpen: action.payload
        }
    case 'selectedJobDocumentId':
      return {
        ...state,
        selectedJobDocumentId: action.payload
      }
    default:
      return state
  }
}
Enter fullscreen mode Exit fullscreen mode

The idea is to automatically take the State type to create the Actions type.

I needed a utility type that takes in an unknown type and spits out a Union with a specific shape to achieve this behavior.

So, a clear use case for Generics and Mapped Types.

🤔 Why? Because generics are the way to write reusable types.

More on that in this Twitter thread

Mapped Types:

The main idea of this is to take the properties > of a type T to create a new type by using those > properties in another way

Let's create a new Unionize utility type that will take a generic named T that extends an object.

The extends keyword here acts as a way to restrict the type of T to be like an object

This type will iterate over the keys of T and map those to a new shape where each key of T will hold a new object shape.

/**
 * Create an Union type from an Object type
 * that will use the Object key as `type` entry and the
 * Object value as `payload`
 */
type Unionize<T extends object> = {
    [k in keyof T]: { type: k; payload: T[k] };
}[keyof T];
Enter fullscreen mode Exit fullscreen mode

Let's use it!!

type State = {
  searchKeyWords: string;
  isSlidingPanelOpen: boolean;
  selectedJobDocumentId: number;
}

/**
 * Create an Union type from an Object type
 * that will use the Object key as `type` entry and the
 * Object value as `payload`
 */
type Unionize<T extends object> = {
    [k in keyof T]: { type: k; payload: T[k] };
}[keyof T];

// I want to create this

type Actions = Unionize<State>

/// So it can be used like this
function reducer(state: State, action: Actions) {
  switch(action.type){
    case 'searchKeyWords':
      return {
        ...state,
        searchKeyWords: action.payload
      }
    case 'isSlidingPanelOpen':
      return {
          ...state,
          isSlidingPanelOpen: action.payload
        }
    case 'selectedJobDocumentId':
      return {
        ...state,
        selectedJobDocumentId: action.payload
      }
    default:
      return state
  }
}
Enter fullscreen mode Exit fullscreen mode

Check it out in the typescript playground

Follow me on Twitter ❤️ Support my content

AWS Q Developer image

Your AI Code Assistant

Ask anything about your entire project, code and get answers and even architecture diagrams. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Start free in your IDE

Top comments (0)

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay