Generate types based on properties of a nested interface dynamically

Consider the setup provided:

enum FormGroups {
  customer = 'customer',
  address = 'address',
}

interface Customer {
  'firstName': string;
}

interface Address {
  'street': string;
}

interface SomeFormEvent {
  valid: boolean;
  forms: {
    [FormGroups.customer]: {
      values: Customer,
    },
    [FormGroups.address]: {
      values: Address,
    }
  }
}

Here is what I intend to use:

type Forms = Customer | Address

This, however, is a static approach. If a new form is added in SomeFormEvent in the future like so:

interface SomeFormEvent {
  valid: boolean;
  forms: {
    [FormGroups.customer]: {
      values: Customer,
    },
    [FormGroups.address]: {
      values: Address,
    },
    // a form is added here:
    [FormGroups.preferences]: {
      values: Preferences,
    },
  }
}

I would need to manually update the 'Forms' type as follows:

// manually have to add 'Preferences'
type Forms = Customer | Address | Preferences

Is there a more dynamic way to create the Forms type?

I've attempted the following:

enum FormGroups {
  customer = 'customer',
  address = 'address',
}

interface Customer {
  'firstName': string;
}

interface Address {
  'street': string;
}


interface SomeFormEvent {
  valid: boolean;
  forms: {
    [FormGroups.customer]: {
      values: Customer,
    },
    [FormGroups.address]: {
      values: Address,
    },
  }
}

type Forms = { [K in keyof SomeFormEvent['forms']]: SomeFormEvent['forms'][K]['values'] }

function foo(): Forms {
    return {
        // error: Type '{ firstName: string; street: string; }' is 
        //   not assignable to type 'Forms'. Object literal may only 
        //   specify known properties, and 'firstName' does not exist 
        //   in type 'Forms'.

        firstName: 'sdfdsf',
        street: 'sdffds'
    }
}

However, this approach does not work.

Answer №1

Affirmative, the formation of this alliance is achievable through the utilization of indexed access types.

type Forms = SomeFormEvent["forms"][keyof SomeFormEvent["forms"]]["values"]
//   ^? Customer | Address

Playground

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 are the steps to extract information from an observable?

Having trouble retrieving data from a request? I've encountered an issue where the data retrieved inside .subscribe in an observable function is returning as undefined when trying to access it outside the function. It's quite frustrating! Here i ...

Enhancing Styled Components in Material-UI with custom props and themes using Typescript

I am exploring the use of the Material UI styled components API to incorporate both a custom theme and some props into a specific custom element. Although I have managed to get either a custom theme or props working individually, I am struggling to make t ...

Mocking store.dispatch in Jest with TypeScript did not result in any function calls being made

Testing Troubles I'm a beginner in the world of testing and I'm facing some challenges. Despite going through all the documentation on jest, I couldn't find information specific to TypeScript cases. Currently, I'm on a quest to figure ...

Simple steps to transform the "inputs" syntax into the "@Input" property decorator

There's this code snippet that I need to modify: @Component({ selector: 'control-messages', inputs: ['controlName: control'], template: `<div *ngIf="errorMessage !== null">{{errorMessage}}</div>` }) Is the ...

Angular fails to retrieve the data from an Object

I have both backend and frontend applications. When I attempt to retrieve information about the 'Probe' object, I can see its fields: https://i.stack.imgur.com/TJQqI.png However, when I try to access this information in Angular, I receive an und ...

Obtain PDF File using Typescript

I am attempting to use an AJAX Post to download a PDF file and return the templateFile Model. However, I am encountering an error where it cannot convert type TemplateFileDto to IhttpActionResult. Should I consider returning something different? Any assist ...

Typescript - neglecting a package that lacks typings

I am considering using an open source package that does not have TypeScript bindings. After checking the linked resource, I was unable to find a solution. Although I attempted to use @ts-ignore, it did not function as expected. Could someone please prov ...

Title remains consistent | Angular 4

Struggling to change the document title on a specific route. The route is initially set with a default title. { path: 'artikel/:id/:slug', component: ArticleComponent, data: {title: 'Article', routeType: RouteType.ARTICLE, des ...

Can one obtain a public IP address using Typescript without relying on third-party links?

Though this question has been asked before, I am currently working on an Angular 4 application where I need to retrieve the public IP address of the user's system. I have searched on Stackoverflow for references, but most posts suggest consuming a th ...

Executing Cross-Component Communication in Angular 7: A Quick Guide

I've encountered a challenge with a checkbox in the header component. If the checkbox is checked, I need to display an alert message when the application loads. The tricky part is that the checkbox is linked to the home component. Therefore, if I am o ...

What is a superior option to converting to a promise?

Imagine I am creating a function like the one below: async function foo(axe: Axe): Promise<Sword> { // ... } This function is designed to be utilized in this manner: async function bar() { // acquire an axe somehow ... const sword = await foo ...

When utilizing a 'Token' in the provider() aliasing within Angular 2, the Typescript compiler may display an error message stating 'Unresolved variable or type'. This issue can arise when defining

When working with Typscript, I've encountered an issue where it can't handle a 'Token' in the context of an Angular2 provide() aliasing function. I'm unsure if there's a specific setting in the typescript compiler to address t ...

Invoke a custom AWS CodeBuild project in CodePipeline using a variety of parameters

Imagine having a CodePipeline with 2 stages structured like this: new codepipeline.Pipeline(this, name + "Pipeline", { pipelineName: this.projectName + "-" + name, crossAccountKeys: false, stages: [{ stageName: &apos ...

Handling onChange events for several typescript <Select> elements

As a non-TS developer, I'm delving into the realm of multiple selects and dropdown menus with Material-UI's select component. Progressing from a basic setup, I successfully implemented a single select but now face a challenge in adding another dr ...

React Redux Bundle with Hot Reload Feature

Working on a project written in TypeScript with the React and Redux framework, I'm familiar with webpack and its middleware libraries for hot reloading. My question arises when considering how my TypeScript code is first converted to JSX through gulp ...

The parameter type ‘DocumentData’ cannot be assigned to type ‘never’ in this argument

I've been struggling to find a solution to my issue: Ts gives me an error: Argument of type 'DocumentData' is not assignable to parameter of type 'never' I attempted the solution I found on this page: Argument of type 'Docume ...

The object is not a valid function

Within this class object, I have an instance of a class that I am unable to call its functions within. Despite the IDE allowing me to call the getPoistionDiagram function: export class NodeW { childrenIds: string[]; diagram?: { coordinates: { ...

Step-by-step guide to initializing a project using React with Typescript and a functional server-side script

I am working on a project that involves a React Typescript app (created using Create React App). In this project, I need to have an executable script that can run alongside the React app. Both the app and the script are intended to only run on local machin ...

Using Typescript to implement a conditional return type and ensuring that the value types are consistent together

I am working with a useSelectedToggle hook that helps in connecting the UI state to the open/closed status of a dialog where it will be displayed. The toggle defines the value as (T) when it is open, and null when it is closed. How can I enforce stricter ...

What methods are available to prevent redundant types in Typescript?

Consider an enum scenario: enum AlertAction { RESET = "RESET", RESEND = "RESEND", EXPIRE = "EXPIRE", } We aim to generate various actions, illustrated below: type Action<T> = { type: T; payload: string; }; ty ...