typescript locate within the union type in the mapping expression

Consider the following:

type X = { label: 'Xlabel', X_id: 12 };
type Y = { label: 'Ylabel', Y_id: 24 };
type Z = { label: 'Zlabel', Z_id: 36 };

type CharSet = X | Y | Z;

I am looking for

type CharSetByLabel = Map<CharSet>; /* { Xlabel: X; Ylabel: Y; Zlabel: Z; } */
.

I attempted this approach and it worked well for a single type, but struggled with unions as I could not narrow down T to each individual item (it resulted in

{ Xlabel: CharSet; Ylabel: CharSet; Zlabel: CharSet; }
).

type $withLabel = { label: string; }
type Map<T extends $withLabel> = {
  [P in T['label']]: T
};

I also tried this method, however, it was unable to infer U to a usable value.

type Map<T extends $withLabel> = {
  [P in T['label']]: P extends T['label'] ? infer U : never;
};

Answer №1

In the past (prior to TypeScript 4.1), it was necessary to calculate the specific member of any union in T that corresponds to the one with the P tag. You can utilize the Extract<T, U> utility type for this purpose:

type Map<T extends $withTag> = {
  [P in T['tag']]: Extract<T, { tag: P }>
};

type MappedAll = Map<All>;
/* type MappedAll = {
  Atag: A;
  Btag: B;
  Ctag: C;
} */

TypeScript 4.1 introduced key remapping in mapped types, making it possible to simplify the above as follows:

type Map<T extends $withTag> = {
  [U in T as U['tag']]: U
};

type MappedAll = Map<All>;
/* type MappedAll = {
  Atag: A;
  Btag: B;
  Ctag: C;
} */

Essentially, you are iterating the union T itself with U, and mapping the key as U['tag']; therefore, on the value side of the property, you simply use U.

Playground link to code

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

Stop fullscreen mode in Angular after initiating in fullscreen mode

Issue with exiting full screen on Angular when starting Chrome in full-screen mode. HTML: <hello name="{{ name }}"></hello> <a href="https://angular-go-full-screen-f11-key.stackblitz.io" target="_blank" style=& ...

Angular 5's data display glitch

Whenever I scroll down a page with a large amount of data, there is a delay in rendering the data into HTML which results in a white screen for a few seconds. Is there a solution to fix this issue? Link to issue I am experiencing HTML binding code snippe ...

Verifying currency in mat-input field

I need help implementing validation for inputting prices on a form. For example, if a user types in $20.0000, I want a validation message to appear marking the input as invalid. Would this type of validation require regex, and if so, how would I go about ...

What are some effective ways to create a flexible framework in Typescript for Node.js applications utilizing the native MongoDB driver?

When using node.js and the native mongodb driver, is there a way to implement a schema/schemaless structure by utilizing classes or interfaces with Typescript (ES6)? For instance, if we have a collection named users and perform actions like ...

Essential parameters needed in a Typescript function signature

My code includes the following type definition: type FuncWithRequiredParams = (a: number, b: number, c:string) => void const func1: FuncWithRequiredParams = (a: number, b: number, c: string) => {} // This is functional const func2: FuncWithRequiredP ...

An issue has occurred where all parameters for the DataService in the D:/appangular/src/app/services/data.service.ts file cannot be resolved: (?, [object Object])

Upon running the command ng build --prod, an error is encountered. Error in data.service.ts: import { BadInput } from './../common/bad-input'; import { AppError } from './../common/app-error'; import { Injectable } from '@angular ...

Get the most recent two files from a set

I am currently facing a challenge in retrieving the first 2 documents from a collection in google cloud firestore. My current approach involves using the timestamp of the latest document and then calculating the time range to fetch the desired documents. l ...

The Static Interface Binding in TypeScript

I have inquired about how to extend the static functionality of existing objects in JavaScript (using TypeScript). In all examples provided here, I am utilizing Object The code below showcases a polyfill definition for ECMAScript's Object.is function ...

Exploring Angular 4 with the power of Rangy modules

I've recently started working with Angular 4 and decided to create a basic app by forking the Angular quickstart. Now, I'm facing a challenge as I try to incorporate Rangy into my project. In my package.json, the dependencies are listed as follo ...

Arrow functions do not function properly with Typescript decorators

I've created a typescript decorator factory that logs the total time taken to execute a function, along with the actual function execution results and parameters passed to the decorator. For example: export function performanceLog(...args: any[]) { ...

struggling to implement dynamic reactive forms with Angular

Currently, I am experimenting with building a dynamic reactive form using Angular. While I have successfully implemented the looping functionality, I am facing some challenges in displaying it the way I want. <form [formGroup]="registerForm" (ngSubmit) ...

What could be causing the error in Angular 2 when using multiple conditions with ng-if?

My aim is to validate if the length of events is 0 and the length of the term is greater than 2 using the code below: <li class="more-result" *ngIf="events?.length == 0 && term.value.length > 2"> <span class="tab-content- ...

Show the value in Angular in a dynamic way

My template needs to display the text 'Passed' only if item.name === 'michael' is not true. The component receives data in an array called courses[] from its parent. There are two interfaces, Courses and Teachers, where each course ID h ...

Implementing Server-Side API Response Caching in React-Query and Next JS

My server-side rendering setup with react-query is working smoothly. I am aware that react-query stores a cache on the client side to serve data if the query key is fresh and available. Here is the code snippet depicting this setup - // pages/_app.tsx imp ...

Exploring React State Management: Leveraging the Context API as a centralized store for

Currently, I am developing a React web application using TypeScript. To enhance the State Management, I decided to implement React Hooks and Context API by following a concise tutorial that I came across here. Despite diligently following the tutorial, my ...

The introduction of an underscore alters the accessibility of a variable

When working in Angular, I encountered a scenario where I have two files. In the first file, I declared: private _test: BehaviorSubject<any> = new BehaviorSubject({}); And in the second file, I have the following code: test$: Observable<Object& ...

Using a Typescript variable prior to its assignment

I encountered an issue in my Typescript / ReactJS project displaying the error message Variable 'myVar' is used before being assigned. TS2454 This problem arises with my TS version 4.2.3, appearing both in my IDE and during code execution. Inte ...

A guide on implementing getStaticProps using TypeScript in Next.js

Why am I consistently receiving undefined results when attempting to retrieve all posts from my backend? What could be causing this issue? import { AppContext } from '@/helpers/Helpers' import axios from 'axios' import { GetStaticProps} ...

Issue with extending mongoose.Document properly in NodeJS and TypeScript using a custom interface with mongoose

I recently started learning Typescript and tried to follow this guide to help me along: After following the guide, I implemented the relevant code snippets as shown below: import { Document } from "mongoose"; import { IUser } from "../interfaces/user"; ...

Uploading Boolean Values from Switch Input (React/Typescript)

I'm facing an issue while trying to post the state value of a switch input toggle control. Whenever I use the submitRecommendation() function through a button click, I encounter a JSON parse error: Cannot deserialize instance of `boolean` out of START ...