Converting a Union to Intersection in Typescript

enum keyEnumNew {
    firstItem = 1,
    secItem = 2,
    thirdItem = 3
};

enum firstEnum {
    x = 'x',
    y = 'y',
};

enum secEnum {
    m = 'm',
    n = 'n',
};

type firstAndSecEnums = firstEnum | secEnum;

type keyObject = {
    [keyEnumNew.firstItem]: { value: firstEnum },
    [keyEnumNew.secItem]: { value: secEnum },
    [keyEnumNew.thirdItem]: { value: firstAndSecEnums },
};

type getKeyValue<T extends keyEnumNew> = keyObject[T]['value'];

type getKeyValueResult1 = getKeyValue<keyEnumNew.thirdItem | keyEnumNew.secItem> // Result secEnum | firstEnum
// Expected Result secEnum.
type getKeyValueResult2 = getKeyValue<keyEnumNew.thirdItem | keyEnumNew.firstItem> // Result firstEnum | secEnum
// Expected Result firstEnum.
type getKeyValueResult3 = getKeyValue<keyEnumNew.secItem | keyEnumNew.firstItem> // Result firstEnum | secEnum
// Expected Result never;

It was anticipated that the outcome would be an intersection rather than a union. The expected result is a value common to all resulting properties. Any assistance on this matter would be greatly appreciated.

Answer №1

If you are using TypeScript 2.8 or above, it is possible to convert unions into intersections. A suggested approach for your case would be:

type UnionToIntersection<U> =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;

// Instead of T[K], use Lookup<T, K> when the compiler struggles to verify that K is a key in T
type Lookup<T, K> = K extends keyof T ? T[K] : never;

type getKeyProp<T extends keyEnum> = Lookup<UnionToIntersection<keyPropObj[T]>, 'prop'>;

This should give you the desired types:

type getKeyPropResult1 = getKeyProp<keyEnum.thirdKey | keyEnum.secKey> // secPropEnum.
type getKeyPropResult2 = getKeyProp<keyEnum.thirdKey | keyEnum.firstKey> // firstPropEnum.
type getKeyPropResult3 = getKeyProp<keyEnum.secKey | keyEnum.firstKey> // never.

I hope this explanation helps. Best of luck with your implementation!

Answer №2

If you're looking to find the commonality between different types, one way is to intersect them manually:

type CommonPropResult1 = getKeyProp<keyEnum.thirdKey> & getKeyProp<keyEnum.secKey>
type CommonPropResult2 = getKeyProp<keyEnum.thirdKey> & getKeyProp<keyEnum.firstKey>
type CommonPropResult3 = getKeyProp<keyEnum.secKey> & getKeyProp<keyEnum.firstKey>

For a less elegant but functional approach that handles up to 6 keys:

type SingleCommonProp<T extends keyEnum> = keyPropObj[T]['prop'];
type CommonPropIntersection<
    T1 extends keyEnum | null = null,
    T2 extends keyEnum | null = null,
    T3 extends keyEnum | null = null,
    T4 extends keyEnum | null = null,
    T5 extends keyEnum | null = null,
    T6 extends keyEnum | null = null,
> = (T1 extends keyEnum ? SingleCommonProp<T1> : unknown) &
    (T2 extends keyEnum ? SingleCommonProp<T2> : unknown) &
    (T3 extends keyEnum ? SingleCommonProp<T3> : unknown) &
    (T4 extends keyEnum ? SingleCommonProp<T4> : unknown) &
    (T5 extends keyEnum ? SingleCommonProp<T5> : unknown) &
    (T6 extends keyEnum ? SingleCommonProp<T6> : unknown);

type secondCommonProp = CommonPropIntersection<<keyEnum.secKey>;
type CommonPropResult1 = CommonPropIntersection<<keyEnum.thirdKey, keyEnum.secKey>>
type CommonPropResult2 = CommonPropIntersection<<keyEnum.thirdKey, keyEnum.firstKey>>
type CommonPropResult3 = CommonPropIntersection<<keyEnum.secKey, keyEnum.firstKey>>

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

Creating a dynamic table in HTML and Angular is a simple process that involves utilizing the

How can I create an HTML table dynamically without knowing the template of each row in advance? Sometimes it may have 2 columns, sometimes 4... I am looking for something like this: <div> <h1>Angular HTML Table Example</h1> < ...

Saving a boolean value and a number to Firestore in an Angular application

In my Angular 5 typescript project, I have a form with various input fields and selections. Here is how I am capturing the form values: let locked: boolean = (<HTMLInputElement>document.getElementById("locked")).value; let maxPlayers: number = (& ...

Tips for converting a string array constant into a union type

I have a string array that I want to use to create a new type where the properties correspond to the elements in the array. There are different types of arrays and I have a function that generates different output types based on the input array. const RG ...

javascript assign array to object key

Looking at this basic array: const arr = [ { "id": 2, "color": "red" }, { "id": 1, "color": "blue" }, { "id": 2, "color": "yellow" ...

Is there a way to subscribe to various observables simultaneously in Angular 2, and then pause until fresh data is available on each of them?

I have an Angular component that relies on 3 services, each of which has an observer I can subscribe to. The view of the component needs to be updated whenever there are changes in the observed data, which occurs through websockets (feathers.js). I want th ...

Applying Multiple Conditions to setCellProps in Material-UI

I am facing an issue with a data-table that is not in a class extending the React.Component, unlike some examples I have come across. My goal is to setCellProps based on certain conditions as outlined below: If utilization is less than or equal to 50, the ...

Utilizing Typescript for directive implementation with isolated scope function bindings

I am currently developing a web application using AngularJS and TypeScript for the first time. The challenge I am facing involves a directive that is supposed to trigger a function passed through its isolate scope. In my application, I have a controller r ...

Typescript's Accessor decorator ensures that the decorated code is executed only once, fetching the previously calculated value for any subsequent calls

The topic discussed here originates from a previous discussion on a method decorator in Typescript. In some scenarios, there are `get` methods in a Typescript class that involve intensive computations. Some of these methods always return the same result an ...

Shattered raw emotion

Does anyone have any insight on how to resolve this error? I've hit a roadblock trying to figure out the issue in the message below. Here is the snippet of code: :label="` ${$t('cadastros.clientes.edit.status')}: ${cliente.status === ...

What are the potential downsides of using ID to access HTML elements in React TypeScript?

During my previous job, I was advised against accessing HTML elements directly in React TypeScript using methods like getElementById. Currently, as I work on implementing Chart.js, I initially used a useRef hook for setting up the chart. However, it appear ...

Utilize an exported class as a type within a .d.ts file

I have two classes, ./class1.ts and ./class2.ts, with the following structure: export class Class1{ ... } and export class Class2{ ... } In my file ./run.ts, there is a function that accepts a class input function doSomething(klass: ClassType){ l ...

Unable to locate identifiers 'Let' (TS2304), 'headers' (TS2552), and 'options' in a TypeScript script

I am new to using Angular and Ionic. While following a tutorial, I encountered the following errors: Cannot find name ‘Let’ (TS2304) Cannot find name ‘headers’. Did you mean ‘Headers’? (TS2552) Cannot find name ‘options’. Did you mean ‘ ...

Expanding the functionality of an external module using d.ts in a TypeScript project

Currently, I am in the process of developing a nodejs application using typescript with multiple external libraries such as express.js. Like many other libraries, express is also designed to be extendable. I am looking to enhance it by including a custom ...

What are some ways to use SWR for mutating data specific to a certain ID?

I have scoured the internet for answers to no avail. It's baffling because I expected this issue to be quite common. Take, for instance, the scenario where we need to retrieve a post with a specific id: const { data } = useSWR(`/api/post/${id}`, fetc ...

Importing a class from a JavaScript file in Typescript: a step-by-step guide

I need help with the following: Importing a js file that defines a class: ./myClass/index.js Declaring the public methods of MyClass (unsure of where to do this, whether in index.ts or another declaration file) Creating a typescript file that exposes the ...

Event typeORM on afterUpdate in NestJS

After every update of my data in the log table, I want to insert an entry into another table. To achieve this, I have created an EntitySubscriberInterface. The event is triggering correctly, but the entity array does not include the updated id. async afte ...

Testing Jasmine with objects that contain optional properties

In the IData interface, there are optional properties available. interface IData { prop1: string, prop2?: string } setObj(){ prop1 = 'abc'; prop2 = 'xyz'; let obj1 : IData = { prop1: this.prop1, ...

Deciphering the SessionProvider error: When "useSession" isn't recognized as a function

I recently started diving into React and NextJS, but I've been able to piece things together with the knowledge I have. Recently, I added social login functionality using Lucia auth and now I'm looking to implement a session provider to allow ac ...

Service Registry with TypeScript type safety

Is there a way to implement a type-safe service registry in Typescript? I want a function that can return a specific type based on the argument provided. For example: get("a") should return an object of type ServiceA. get("b") should re ...

Passing data between parent and child components within an Angular application using mat tab navigation

I am currently working on a project, which can be found at this link. Current Progress: I have implemented a mat tab group with tabs inside the app-component. When a tab is clicked, a specific component is loaded. Initially, most of the data is loaded in ...