Transforming a TypeScript union type into an object type

Can a type like this be translated:

export type UnionType = {
        element:
            | { $case: 'a'; a: number }
            | { $case: 'b'; b: string }
            | { $case: 'c'; c: boolean };
    };
    

into a type of this kind:

type OneOfConverter<T> = any; // TODO

    type ObjectType = OneOfConverter<UnionType>;

    // type ObjectType = {
    //     a: number;
    //     b: string;
    //     c: boolean;
    // };
    

Typescript playground

Answer №1

Here's a suggestion that might be helpful:

type OneOfConverter<T extends { element: { $case: PropertyKey } }> = {
    [U in T["element"] as U["$case"]]: U["$case"] extends keyof U ? U[U["$case"]] : never
}

This code snippet utilizes key remapping in mapped types to go through the union members of T['element'] and assign each member to a type parameter U. The key we are interested in is U["$case"].

We want to access the value within U using this key, so we do U[U["$case"]]. However, to handle cases where the property may not exist, we perform a conditional type check

U["$case"] extends keyof U
to make sure the key exists in U. If it does, we fetch the property value as U[U["$case"]]; otherwise, we return never.

Let's test it out:

type ObjectType = OneOfConverter<UnionType>;
// type ObjectType = {
//     a: number;
//     b: string;
//     c: boolean;
// };

Seems to be working fine!

Playground link to view 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

How to configure VSCode for automatically transpiling TypeScript and launching NodeJS debugger with just one press of the F5 key?

Working with VSCode+TypeScript+NodeJS can feel overly complex compared to a C# project in Visual Studio. Just hitting F5 in C# compiles the project and initiates debugging. How can I configure VSCode to do the same for TypeScript+NodeJS? What am I missing ...

Combining Bazel, Angular, and SocketIO Led to: Unforeseen Error - XMLHttpRequest Not Recognized as Constructor

I am looking to integrate ngx-socket-io into my Angular application. I utilize Bazel for running my Angular dev-server. Unfortunately, it seems that ngx-socket-io does not function properly with the ts_devserver by default. Upon checking the browser consol ...

Mocking a third-party callback function in Jest for method implementation

Utilizing Nest + Cognito for user authentication in an application, I have a method within my Authentication service that requires testing/mocking: async cognitoRegister(userPool: CognitoUserPool, { name, password, email }: AuthRegisterInput): ...

Having difficulty with sending just the selected value using TypeScript

I've encountered an issue with sending the value of a select input to my database while working with Vue, Quasar, and TypeScript. Within a modal, I have name and age inputs along with a select that chooses a category. However, when attempting to send ...

Efficiently loading data in a table with a universal filter feature using Angular with PrimeNG

Recently, I managed to set up a datatable with the functionalities of both Lazy loading and global filter. Utilizing PrimeNG components for this implementation was a breeze. However, an issue surfaced where the global filter ceased to function when lazy lo ...

Unable to locate the name 'JSON' in the typescript file

I have been working on an angular application where I have implemented JSON conversion functionalities such as JSON.stringify and JSON.parse. However, I encountered an error stating 'Cannot find name 'JSON''. Furthermore, there is anoth ...

The argument provided does not match the expected parameters

import { Component } from '@angular/core'; import { IonicPage, NavController, NavParams } from 'ionic-angular'; import { EventDetail } from '../../models/event-detail/event-detail.interface'; import { AngularFireDatabase, Angu ...

How to achieve dynamic class instantiation through constructor injection in Angular 8?

Despite my efforts to find a solution, my understanding of Dependency Injection in services is still limited, making it challenging to get this thing working. I'm left wondering if there's any way to make it work at all. My current setup involve ...

Mouse event listener includes timeout function that updates a global variable

I'm currently working on a function that gets activated by a mouse click, but there's a 10-second cooldown period using setTimeout() before it can be triggered again. However, after the timeout, my variable doesn't get set to the correct boo ...

Extracting the Hidden Gems in a Nested Object

My goal is to extract a specific value from a two-level deep object data structure. To begin, I am storing the data in a variable within a function, like so: getTargetId() { if (this.authenticationService.isAuthenticated()) { const userInfo = ...

Differences between Angular components and TypeScript classes in models

In my observation, I have noticed that in several instances, manual models are being created for components to specifically manage the data. Despite this, the component already contains a ts class along with the html and css data. Shouldn't the task ...

Loop through an array of strings

When I receive the data as a string[] https://i.sstatic.net/ttyag.png However, when I attempt to loop over it subUrl(arr) { for(let i of arr) { console.log(i); } } No output is being logged. What could be causing this issue? ...

Experiencing unexpected behavior with Next.JS getStaticProps functionality

I am currently working on a website where I want to display dynamic feedback as cards. However, my fetchData variable within the Home function is always returning undefined. Here's the code snippet I have tried: import UserCard from "../component ...

How to send multiple queries in one request with graphql-request while using getStaticProps?

I am currently utilizing graphCMS in combination with NextJS and have successfully implemented fetching data. However, I am facing an issue where I need to execute 2 queries on the homepage of my website - one for all posts and another for recent posts. q ...

Using Webpack to bring in AngularJS modules

Our current project is transitioning from AngularJS to Angular 4, and as part of this process, we are first rewriting everything in TypeScript and converting AngularJS components. To facilitate this transition, we have set up a new project using AngularJS ...

Why is the value not being assigned by the Angular component from the observable service getter?

I am currently working on developing a filter set, and I am facing an issue with the salesChannels array content in my view. The array only gets populated after clicking a button that triggers the test() function. Interestingly, the first time I log the ar ...

Directing users to varying pages based on a particular criteria

As we continue to develop our application, we are creating various pages and need to navigate between them. Our current framework is Next.js. The issue we are facing involves the Home page: when transitioning from the Home page to another page (such as pa ...

Using TypeScript to define parameter types to update an object's key and value

I need assistance in creating a function that can update an object's value based on the provided key and new value while ensuring type safety. type GroceryStore = { isOpen: boolean; offers: string[]; name: string; }; const myGroceryStore: ...

Vue will display only the most recent component that has been registered

In Vue, it always renders the last registered component and ignores any others, even if they are not used at all. //main.ts import Vue from 'vue'; Vue.component('component-one', require('./components/ComponentOne.vue')); ...

When reaching for the child component in TypeScript, the function document.getElementById may

I am facing an issue with adding "CubeView" from elmarquez/threejs-viewcube to my project. I have created a component and the code for the component is as follows: import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'; ...