Exploring object recursion using Typescript types

I have defined a Module with a MetaData type and a mapping object for child/nested Modules:

type Module<T, C extends Children> = {
    metaData: T;
    children: C;
};

type Children = {
    [key: string]: Module<any, any>;
}

type ExtractMetaData<M extends Module<any, any>> = M extends Module<infer T, any> ? T : never;

type ExtractChildren<M extends Module<any, any>> = M extends Module<any, infer C> ? C : never;

Next, I create three modules, A, B, and C, where C is a child of B and B is a child of A:

type C = Module<number, {}>;

type B = Module<boolean, {
  c: C;
}>;

type A = Module<string, {
  b: B;
}>;

Now, I need a utility type called

AllMetaData<T extends Module>
that will give me a union of all the MetaData types in a Module tree. For example, AllMetaData<C> should return the type number, AllMetaData<B> should be number | boolean, and AllMetaData<A> should be number | boolean | string.

Here's my attempt at creating this type:

type AllMetaData<
  MODULE extends Module<any, any>,
  CHILDREN = ExtractChildren<MODULE>,
  METADATA = ExtractMetaData<MODULE>,
> =
  | METADATA
  | {
      [KEY in keyof CHILDREN]: CHILDREN[KEY] extends Module<any, any>
        ? ExtractMetaData<MODULE>
        : never;
    }[keyof CHILDREN];

However, when I try to use this type:

type Result = AllMetaData<A>;

The Result turns out to be just string, instead of the expected union of all the MetaData types in A's tree.

What could be causing this issue with my AllMetadata type?

Playground link

Answer №1

You've made 2 errors.

  1. Instead of using MODULE on line 9, try using CHILDREN[KEY]
  2. Replace ExtractMetaData with AllMetaData on line 9

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

Angular 5: Issues with retrieving response using HttpClient's get request

Alright, so typically I work with Angular 1.*, but I decided to dive into Angular 5 and man, it's been a bit of a challenge. It feels unnecessarily complex, but oh well... So I'm trying to make an HTTP call, and I have this node API that is retu ...

Tips on how to incorporate a .js file into my .tsx file

I ran into an issue with webpack displaying the following message: ERROR in ./app/app.tsx (4,25): error TS2307: Cannot find module './sample-data'. The imports in my code are as follows: import * as React from 'react'; import * ...

What is the best way to refresh NGRX data?

There are two models in a one-to-many relationship: export interface GroupModel { id: number; name: string; userIds?: number[]; } export interface UserModel { id: number; name: string; groupId?: number; } An issue arises when updating either m ...

Accessing property values from a map in Angular

Is there a way to retrieve a property from a map and display it in a table using Angular? I keep getting [object Object] when I try to display it. Even using property.first doesn't show anything. //model export interface UserModel { room: Map ...

Utilizing NgModelGroup nesting in various components for improved data management

Whenever I attempt to nest NgModelGroup inside another NgModelGroup, Angular seems to just ignore it. I'm currently utilizing Angular 12 and Template-driven Forms. Here is how my code appears: app.component.html <form #form="ngForm"> ...

Is there a method to retrieve Mui state classes easily?

One thing I really appreciate is the way to style mui-components with their class names. I'm curious if there's a method to access state classes like Mui-checked using a variable. Let me delve deeper into this: I have a styled component that lo ...

Alert: Angular has detected that the entry point '@libray-package' includes deep imports into 'module/file'

Recently updated the project to Angular 9.1 and now encountering multiple warnings from the CLI regarding various libraries, such as these: Warning: The entry point '@azure/msal-angular' includes deep imports into 'node_modules/msal/lib-com ...

Using TypeScript to Import Modules without Default Exports (CommonJS)

Can a module that is defined without a default export be imported using import module from 'module'; and then compiled to commonjs? An answer on Stack Overflow suggests that it might be possible with the use of the --allowSyntheticDefaultImports ...

What are the advantages of using the fat arrow instead of straight assignment?

Here we have a code snippet sourced from the 30 seconds of code website. This example, intended for beginners, has left me feeling stumped. The question arises: const currentURL = () => window.location.href; Why complicate things when you could just ...

What is the best way to optimize a search for objects with extensive field arrays?

Recently, I've been working with an object schema that includes an array field to store ids for objects from a separate collection. This array has the potential to contain thousands of ids. Up until now, I have been excluding this field using .select( ...

Exploring Function Overriding in TypeScript

Currently, I'm working on developing a TypeScript method. import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs'; @Injectable({ p ...

The HTMLInputElement type does not contain a property named 'name'

function handleChange(e) { console.log(e.target.name); } <input name="bb" onChange={handleChange} /> Have you ever wondered why the HTMLInputElement element does not have a name attribute in React? ...

How to instantiate an object in Angular 4 without any parameters

Currently, I am still getting the hang of Angular 4 Framework. I encountered a problem in creating an object within a component and initializing it as a new instance of a class. Despite importing the class into the component.ts file, I keep receiving an er ...

Adjusting the timing of a scheduled meeting

Is there a way for me to update the time of a Subject within my service? I'm considering abstracting this function into a service: date: Date; setTime(hours: number, mins: number, secs: number): void { this.date.setHours(hours); this.date.s ...

Add a React component to the information window of Google Maps

I have successfully integrated multiple markers on a Google Map. Now, I am looking to add specific content for each marker. While coding everything in strings works fine, I encountered an issue when trying to load React elements inside those strings. For ...

Error in Typescript resulting from conditional rendering with props

Consider this straightforward conditional statement with a component return: let content = movies.length > 0 ? movies.map((movie, i) => <MovieCard key={i} movie={movie} />) : null; Upon running Typescript, an error regarding the 'movie&a ...

An error message stating 'Cannot read the name property of undefined' is being displayed, despite it being expected to be defined

interface InputField { readonly label : string; readonly data : string; readonly displayInline ?: boolean; } class FormField implements InputField { readonly label : string; readonly data : string; readonly displayInline ?: boolean; constru ...

What is the optimal method for navigating through a complex nested object in Angular?

Looking to navigate through a nested object structure called purchase. Within this structure, there is a sub-array named purchaseProducts which contains another sub-array called products along with additional data. What methods do you suggest for efficien ...

How to generate a SHA256 hash of the body and encode it in base64 using Python compared to

I'm aiming to hash the body using SHA256 and then encode it with base64. I'm in the process of converting my code from Python to TypeScript. From what I gathered via a Google search, it seems like crypto can be utilized instead of hashlib and ba ...

Error Encountered with Next.js 13.4.1 when using styled-components Button in React Server-Side Rendering

I am currently working on a React project using Next.js version 13.4.1 and styled-components. One problem I'm facing is with a custom Button component that I've created: import React from 'react'; import styled from 'styled-compone ...