Converting a tagged union to a union type in Typescript can help streamline your code and

I have a tagged union interface that looks like this:

interface Example {
  a: TypeA;
  b: TypeB;
}

My goal is to convert this tagged union into an union type as shown below:

type oneOf<T> = ...

In this new union type,

var example: oneOf(Example); // would be { a: TypeA } | { b : TypeB }

I am struggling to map the type keys into an object with only the key as a parameter. Any suggestions?

Answer №1

Achieving this can be done through a combination of the following techniques:

interface Example {
  a: string;
  b: number;
}

type SingleProperty<T, K extends keyof T> = K extends any ? {[Prop in K]: T[Prop]} : never
type UnionOfProperties<T> = { [K in keyof T]: SingleProperty<T, K> }[keyof T];
type ExamplePropertiesUnion = UnionOfProperties<Example>

The expected result is as follows:

type ExamplePropertiesUnion = {
    a: string;
} | {
    b: number;
}

However, it's important to note that TypeScript allows the following scenario by default:

var t: ExamplePropertiesUnion = {a: "", b: 42}

This may not always align with our intended behavior, so for stricter type checking, we can use the following variant:

type FixTsUnion<T, K extends keyof T> = {[Prop in keyof T]?: Prop extends K ? T[Prop]: never}
type oneOf<T> = { [K in keyof T]: Pick<T, K> & FixTsUnion<T, K;}[keyof T];
// ok
var z1: oneOf<Example> = { a: "" };
// ok
var z2: oneOf<Example> = { b: 5 };
// error
var z3: oneOf<Example> = { a: "", b: 34 };
// error
var z4: oneOf<Example> = { };

Experiment with the code here

Related questions:

  • TypeScript: How to map union type to another union type
  • How to transform union type into intersection type

Answer №2

type UnionEntry<T> = { [K in keyof T]: { [Q in K]: T[Q] } }[keyof T];

This code snippet achieves the same result as:

type UnionEntry<T> = { [K in keyof T]: Pick<T, K> }[keyof T];

However, when using utility types like Pick, the type inference seems to halt at the point of the utility type and doesn't expand further. Although both methods enforce type correctness for assignments, troubleshooting errors may be less straightforward with Pick unless you are well-versed in its functionality.

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

Using TypeScript to create a function with an argument that is optional based on a condition

I need a function that will only take a second argument when certain conditions are met. let func = <T extends boolean>(arg1: T, arg2: T extends true ? void : string) => {}; func(true); // ERROR Expected 2 arguments, but got 1 func(true, undefin ...

Error message when testing Angular Mat Dialog: The function This.dialogref.updatesize does not exist

I am a beginner in working with Angular. I am currently facing an issue while writing a unit test for mat dialog which is resulting in an error. This is the method in my TypeScript file : isMobileScreen= Observable<BreakpointState>= this.breakpointO ...

What steps can I take to ensure the reliable functioning of this npm script?

Within my npm package, I have these two straightforward scripts: "prebuild": "rimraf dist types", "build": "tsc", Development dependencies rimraf@^5.0.5 and typescript@^5.3.2 are both installed. However, when I run ...

Navigate through Angular 2 array elements

I am facing an issue where I have an array and I need to display only a single object from the array at a time. The goal is to cycle through the array using a button, but I'm struggling to figure out how to display just one object at a time. You can s ...

Guide to updating the file name while downloading in JHipster (Java and Angular)

Here is the snippet of code responsible for opening the file from the controller: openFile(contentType, field) { return this.dataUtils.openFile(contentType, field); } Within the HTML, this function is used to pass in data retrieved from a servic ...

What is the best way to bring in this interface from the React-Particles-JS library?

I have been attempting to segregate my parameters from my JSX within the react-particles-js library. I organize my parameters in an Object: let config = { "particles": { "number": { "value": 50 }, ...

Struggling with TypeScript tests elusive to Jest

I'm encountering a strange error while attempting to write a jest test. TypeError: jest_1.it is not a function 9 | 10 | describe('Health check', () => { > 11 | it('GET works', async () => { Instead of displayi ...

Angular 4 prohibits certain special characters and the number zero

Currently, I am a beginner in Angular 4 and I am working on learning how to search for data from a text box. However, whenever I input special characters like "%" in my code, it triggers an error leading to a crash in my application. Is there any effectiv ...

Angular 6: A class with no 'default' modifier must explicitly specify a name

I am encountering this error in my ts.file, as I delve into the world of Angular/Ionic. Can anyone help identify the possible reasons for this? I have attempted multiple solutions to address it, but unfortunately, none have proven successful. import { Co ...

Utilizing NgClass Within an Attribute Directive in Angular 2.4.0

Is there a way to utilize NgClass within a custom attribute directive to modify the CSS class of the main elements? For example, if I have this code snippet: @Component({ selector: 'my-app', template: ` <div> <div class=" ...

Issue with IE11: Main.js unable to load app.module.js as ./app.module

My angular2 project is currently functioning smoothly in the latest versions of Chrome and Firefox. I am using gulp for my build automation process and systemjs for module loading. However, when I try to access the application in IE11, it fails to load a ...

Is there a way to seamlessly share TypeScript types between my Node.js/Express server and Vite-React frontend during deployment?

I'm currently tackling a project that involves a Node.js/Express backend and a Vite-React frontend. My goal is to efficiently share TypeScript types between the two. How should I configure my project and build process to achieve this seamless type sha ...

A guide on implementing Angular-DataTable within a TypeScript project

Hey everyone, I'm currently working on a TypeScript and Angular application. To create a data table, I decided to use Angular-DataTable. After creating a sample application using it, I added the following code to my Controller: constructor(protecte ...

Developing J2EE servlets with Angular for HTTP POST requests

I've exhausted my search on Google and tried numerous PHP workarounds to no avail. My issue lies in attempting to send POST parameters to a j2ee servlet, as the parameters are not being received at the servlet. Strangely though, I can successfully rec ...

XCODE encountered an issue while attempting to open the input file located at '/Users/name/Desktop/test/appname/node_modules/react-native-compressor/ios/Video/Compressor-Bridging-Header.h'

Encountering an issue while running my project in XCode. I recently added the react-native-compressor package by following the steps mentioned in the installation guide When attempting to run the project in XCode, the error below occurs: <unknown> ...

Identifying modifications to a variable in a React component

I am currently working on implementing a way to detect changes in a variable within a React application. This particular variable is a property of a class and gets set when an asynchronous event occurs. Below, you can find an example of the class I am wor ...

Ensure that the status bar remains visible while in full screen mode on Ionic for both android and iOS devices

Greetings! I am currently developing an application with Ionic/Cordova and I have a question regarding enabling the full screen mode while also displaying the status bar. I have already added the following code to my config.xml file: Could someone provide ...

An error occurred while trying to load the configuration "next/core-web-vitals" for extension

If you're embarking on a new project using NextJs and TypeScript, chances are you may encounter the following error: Failed to load config "next/core-web-vitals" to extend from. Wondering how to resolve this issue? ...

The power of RXJS's combineLatest operator

Upon using the combineLatest operator, I encountered an unexpected response when adjusting the interval duration of the first and second observables. Here is an example of the code: let intObs1$ = interval(1000).pipe(take(3)); let intObs2$ = interval( ...

Errors in type checking observed in app.reducer.ts file for Angular NgRx

I encountered an issue with my login/logout state management setup. The error message I received is as follows: When trying to assign '(state: State | undefined, action: authActions) => State' to type 'ActionReducer<State, Action>& ...