Typescript: A Guide to Mapping Intersections by Type

I have several interfaces such as Foo, Bar, Baz, and I want to create a union of their mapped types where the mapping is consistent (e.g., using Pick).

interface Foo {
  a: 'FooA';
  b: 'FooB';
}

interface Bar {
  a: 'BarA';
  b: 'BarB';
}

interface Baz {
  a: 'BazA';
  b: 'BazB';
}

I can achieve this manually:

type A = Pick<Foo, 'a'> | Pick<Bar, 'a'> | Pick<Baz, 'a'>;
type B = Pick<Foo, 'b'> | Pick<Bar, 'b'> | Pick<Baz, 'b'>;

However, I would like to avoid repeating myself. The following code does not accomplish this as it unions the properties of types and then maps them afterwards:

type Union = Foo | Bar | Baz;

type A = Pick<Union, 'a'>; // creates { a: 'FooA' | 'BarA' | 'BazA' } but I need { a: 'FooA' } | { a: 'BarA' } | { a: 'BazA' }
type B = Pick<Union, 'b'>;

Is there another approach to achieve this?

Answer №1

To take advantage of the distributing behavior of conditional types, you can use the following approach:

type SelectDistributed<T, K extends keyof T> = T extends object ? Select<T, K> : never;

type Choices = Option1 | Option2 | Option3;

type ResultA = SelectDistributed<Choices, 'a'>; // produces Select<Option1, 'a'> | Select<Option2, 'a'> | Select<Option3, 'a'>
type ResultB = SelectDistributed<Choices, 'b'>;

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

What could be causing the issue with my React Native app's release version not opening on a physical Android device?

I encountered an issue while trying to install the Release version of my application. In order to test both the debug and release versions on my physical and virtual devices, I utilized the following commands: ./gradlew assembleDebug, ./gradlew assembleRel ...

Retrieve the object property based on an array of indices

I am looking to create a function that can retrieve a specific property of an object based on an array of property names const getObjectProperty = (arr: string[], object: any) { // This function should return the desired object property } Expected Outco ...

The process of linking a Json response to a table

In my products.components.ts class, I am retrieving Json data into the variable this.Getdata. ngOnInit() { this._service.getProducts(this.baseUrl) .subscribe(data => { this.Getdata=data this.products=data alert(JSON.stringify(this.Getdata)); ...

Why does the onBlur event function in Chrome but fails to work in Safari?

I've encountered a problem with the onBlur event in react-typescript. To replicate the issue, I clicked the upButton repeatedly to increase the number of nights to 9 or more, which is the maximum allowed. Upon further clicking the upButton, an error m ...

Change the property value prior to running TypeScript validation

I possess the following object: const translations = { msg_hello: 'Hello', msg_bye: 'Bye' } In addition, I have a function that is structured as such: const generateTranslation = (partialKey: string): keyof typeof translations ...

Typescript Code Coverage with karma-jasmine and istanbul: A complete guide

I am attempting to calculate the Code Coverage for my typescript Code in karma framework using Istanbul. In the karma.conf file, typescript files are added and through karma typescript-preprocessor we are able to conduct unit testing and code coverage of t ...

react-i18next - The function call does not match any overload when the specified type is `string`

I am currently utilizing react-i18next in conjunction with React and TypeScript. Interestingly, when I attempt to load a property using a string literal and type inference, everything works seamlessly. However, once I specify the type as string, an error i ...

Setting up shortcuts for webpack using lerna and typescript

I have set up a repository to showcase an issue I am facing: https://github.com/vileen/lerna-webpack-typescript-aliases-issue (the app does not start properly, but that's not the main concern). The main question here is how can I enhance importing fr ...

Promise.allSettled() - Improving resilience through retry mechanisms for concurrent asynchronous requests

TL;DR: I'm seeking advice on how to handle multiple promise rejections and retry them a specified number of times when using Promise.allSettled() for various asynchronous calls. Having come across this article: I was intrigued by the following state ...

An object may be null when its type is A or undefined, but we are certain it is not undefined

Since the release of version 4.8.4, the TypeScript compiler has been flagging an issue with the following code: type A = {v: number} function get_the_first<T>(xs: T[]): T | undefined { if (xs.length > 1) return xs[0]; else ...

Exploring the world of TypeScript interfaces and their uses with dynamic keys

I am hopeful that this can be achieved. The requirement is quite simple - I have 2 different types. type Numbers: Number[]; type Name: string; Let's assume they are representing data retrieved from somewhere: // the first provider sends data in th ...

Optimizing image imports through treeshaking while integrating Typescript

One of my components has a structure similar to this: import foo from "./assets/foo.svg"; import bar from "./assets/bar.svg"; const icons = {foo, bar}; type IconTypes = "foo" | "bar"; type IconProps = { ic ...

typescript interface, mandatory if another is present

Is it possible to create an interface with multiple properties where one is required if the other is used? For example: interface MyProps { onPressAll: () => void; icon?: ImageSourcePropType; onPressIcon?: () => void; } What I'm looking ...

Manipulating a <DIV> style within an Angular 8 project

Looking to change the display style? Check out this template: <div style="display: none" #myDiv /> There are 2 methods to achieve this: Method 1: Directly if (1===1) this.myDiv.style.display = "block"; Method 2: Using @ViewChild @ViewChild(&apo ...

Leverage jsencrypt in Ionic 3

Struggling to hash passwords for login on my Ionic 3 app, I attempted using jsencrypt following a tutorial but encountered issues as I couldn't grasp how it works... Here's what I tried : npm install --save jsencrypt import { Component } from ...

The Angular error message InvalidValueError is thrown when the Map function expects a mapDiv of type HTMLElement, but instead receives a

When attempting to initialize Google Maps, I encountered a particular problem. In this div, I am trying to load the map but consistently receiving the same error message. I attempted to use ngAfterViewInit() in case the view wasn't fully loaded befo ...

Ways to rename a sequelize property following a join operation

I am encountering a problem with sequelize ORM. The data returned after joining has a nested object: { "id": 1, "username": "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4125342e2f26252e282220 ...

Prevent Promise / Property not found error in Angular2 by Instantiating Class

When working with my "export class", I encountered an issue that led to a Promise error if I didn't include this line of code: purchase = new Purchase(); right before the constructor. The error indicated that the property "name" was not found. Alth ...

When I utilize a component to create forms, the React component does not refresh itself

One of the components I am working with is a form handling component: import React, { useState } from "react"; export const useForm = (callback: any, initialState = {}) => { const [values, setValues] = useState(initialState); const onCha ...

Typescript: Express RequestHandler variable potentially undefined even after validation within if statement

As I work on a solution for dynamically creating routes before the server fully initializes (not in response to a request, of course), I encountered an interesting issue. Here's a simplified example. In my actual code, there are more parameters like ...