Convert the union into a mapped structure

Starting with the given Union type:

type Union =
  { type: 'A', a: string } |
  { type: 'B', b: number }

The end goal is to transform it into this MappedUnion type:

type MappedUnion = {
  A: { type: 'A', a: string }
  B: { type: 'B', b: number }
}

Here's a snippet of pseudo code to achieve that:

type MappedUnion<item in Union> = {[ i: item['type'] ]: item}

Answer №1

One potential solution could be as follows. While not extensively tested, it appears to be functional.

type Union =
  { type: 'A', a: string } |
  { type: 'B', b: number }

type MappedUnion = {[P in Union['type']]: Union & {type: P}};

const v: MappedUnion = {
  'A': {type: 'A', a: "hello"},
  'B': {type: 'B', b: 3},
}

Unfortunately, this approach falls short; for example:

type MappedUnionTarget = {
  A: { type: 'A', a: string }
  B: { type: 'B', b: number }
}

function cvt1(x: MappedUnion): MappedUnionTarget {
  return x;
}

The resulting error message states

Type '({ type: "A"; a: string; } & { type: "A"; }) | ({ type: "B"; b: number; } & { type: "A"; })' is not assignable to type '{ type: "A"; a: string; }'
. It was expected that TypeScript would recognize that
({ type: "B"; b: number; } & { type: "A"; })
should equate to never.


If you're open to utilizing Typescript 2.8 (not yet officially released, but obtainable through a git pull from the TypeScript repository), which introduces support for the conditional operator ? : at the type level, consider the following workaround:

type FilterType<T, K> = (T extends { type: K } ? T : never);

type MappedUnion = {[P in Union['type']]: FilterType<Union, P>};

This modified implementation of FilterType<T, K> aims to replicate the behavior initially anticipated with T & {type: K}.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you loop through an array of objects in TypeScript without relying on the traditional forEach

Currently, I'm working on an array of objects with the following structure. [ { "matListParent": "CH", "dParent": "CUST1", "isAllSelected": true, "childItems&qu ...

The specified main access point, "@angular/cdk/platform", is lacking in required dependencies

I recently updated my Angular app from version 8 to version 9. After resolving all compilation and linter errors, I encountered one specific issue that is causing me trouble: ERROR in The target entry-point "@angular/cdk/platform" has missing dep ...

TypeScript enum type encompassing all potential values

One thing I have learned is that keyof typeof <enum> will give us a type containing all the possible keys of an enum. For example, if we have enum Season{ WINTER = 'winter', SPRING = 'spring', SUMMER = 'summer', AUT ...

What is the best way to extract information from a button and populate a form in AngularCLI?

I am currently attempting to enhance my Angular App by using a button to transfer information to a form upon clicking, rather than the traditional radio buttons or select dropdowns. My objective is to incorporate HTML content into the button (such as Mat-I ...

A guide on parsing a stringified HTML and connecting it to the DOM along with its attributes using Angular

Looking for a solution: "<div style="text-align: center;"><b style="color: rgb(0, 0, 0); font-family: "Open Sans", Arial, sans-serif; text-align: justify;">Lorem ipsum dolor sit amet, consectetur adipiscing e ...

Navigating through embedded arrays in Angular

JSON Object const users = [{ "name":"Mark", "age":30, "isActive" : true, "cars":{ Owned : ["Ford", "BMW", "Fiat"], Rented : ["Ford", "BMW", "Fiat" ...

What is the best way to retrieve the height and width of a device's display in Angular 2 using Typescript

I came across this code snippet. Do you think it's valid? import {Component} from '@angular/core'; import {Platform} from 'ionic-angular'; @Component({...}) export MyApp { constructor(platform: Platform) { platform.ready().then ...

Navigating through sections in NextJS-14: Utilizing useRef for seamless scrolling

In the past, I had developed an older portfolio website using Vite React + TS and implemented useRef for scrolling to sections from the Navbar. Now, my goal is to transition this portfolio to NextJS 14. I transferred my old components and style folders in ...

The useParams() function encounters difficulty in converting data to number typescript

Whenever I try to convert the heroId type from string to number in my code, I always encounter an error. Here is the code snippet: import useHero from '../../hooks/useHero'; import {useParams} from 'react-router-dom' function Herospag ...

Discovering a method to detect clicks outside of a React functional component

Looking to identify when a click occurs outside of a React functional component. After stumbling upon an article, I followed the provided code but unfortunately, it didn't work as expected. Despite identifying the issue, I am still searching for a so ...

Limit the parameter of a TypeScript method decorator based on the method's type

Is it possible to generically restrict the argument of a method decorator based on the type of the method it is applied to? I attempted to obtain the method's type that the decorator is applied to using TypedPropertyDescriptor<Method>. However, ...

React Color Input: The input format should follow the pattern of "#rrggbb", with rr, gg, and bb being two-digit hexadecimal values

The code is functioning correctly and as expected. The background color of the squares changes when each input is modified, and the squares update once the button is pressed. During development, there was a moment when the warning mentioned appeared brief ...

Show data based on the chosen destination

Recently, I've been working on creating a simple printer manager to monitor the status of all my printers. Although I have successfully displayed all the data, I'm facing an issue while trying to organize it by location. The error message I keep ...

Dismiss the necessity of imports in Angular

I am facing an issue with using a library in Angular, specifically the cubing npm package. This library is designed to run in both the browser and node environments, with specific code for each. I want it to run in the browser, but when compiling with Angu ...

Retrieve input value in Angular 8 using only the element's ID

Can the value of an input be obtained in Angular 8 with TypeScript if only the element's id is known? ...

How can TypeScript be used to update the values and text of an HTML element?

Is it possible to update specific attributes of an html element using typescript? Below is the code snippet: HTML:- <a ref="#" id="userProfileName" style="padding-top: 0px; padding-bottom: 0px; padding-right: 10px; padding-left ...

Can you explain the significance of the @ symbol in TypeScript/Vue?

I've recently embarked on a new VueJS project and stumbled upon some unfamiliar syntax. I have highlighted the lines with comments below. file(example) : MyModule.vue const storeCompte = namespace("compte") // namespace is based on 'no ...

What is the process for including a custom Jasmine matcher definition in Typescript?

I've been searching around for information on creating custom Jasmine matchers using TypeScript and it seems like a common issue. However, none of the solutions I've come across have worked for me. My setup includes: { "typescript": "2.3.2", ...

Storing information in an array based on a specific flag

Currently, I am developing an Angular application where I am dealing with a specific array that contains a flag named "checked". Based on the value of this flag, I need to perform certain manipulations. Here is a snippet of my sample data: const data = [{ ...

Using Typescript to extract and process keys of a certain type from an object

I am dealing with an object type that has keys corresponding to values of various types, including number, string, optional number, and optional string: interface MyObject { mandatoryNumber: number; optionalNumber?: number; mandatoryString: string; ...