A TypeScript generic type that can take in a structure shaped like a tree along with a type that will transform all the different nodes within the tree into a union

Let's imagine a unique tree structure:

type Tree = {
  a: {
    b: {
      c: "d"
    }
  }
}

Now, consider wanting to transform each node in the tree into a union type, say "f". This means the updated tree would look like this:

type Tree = {
  a: {
    b: {
      c: "d" | "f"
    } | "f"
  } | "f"
} | "f"

The objective is to create the above type using a utility called

DescendantsUnionedWith<T, F>
, where T represents the original Tree type and F stands for "f".

To tackle this issue, I initially developed a generic type named ChildrenUnionedWith:

export type ChildrenUnionedWith<O extends object, T> = {
  [K in keyof O]: O[K] | T;
};

Following that, my attempt was to build a recursive deep tree type:

export type DescendantsUnionedWith<Tree extends object, T> = Tree extends object
  ? ChildrenUnionedWith<DescendantsUnionedWith<Tree, T>, T>
  : Tree | T;

Unfortunately, I encountered a circularity error when trying to implement this approach.

If anyone has insights on how I can successfully implement the DescendantsUnionedWith utility type, your help would be greatly appreciated!

Thank you!

Answer №1

Don't pay attention to the output type, it might not accurately reflect the actual data. The test cases are listed below:

If you encounter any issues, please let me know.

type DeepInsert<T, Insert> = {
  [K in keyof T]: T[K] extends object ? DeepInsert<T[K], Insert> | Insert : T[K] | Insert
}

type Tree = {
  a: {
    b: {
      c: "d"
    }
  }
}


type IsEqual<A, B> = [A] extends [B] ? [B] extends [A] ? true : false : false


type test = IsEqual<DeepInsert<Tree, "X">, {
  a: {
    b: {
      c: "d" | "X"
    } | "X"
  } | "X"
}>; // This should return true.


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 is the method for importing the merge function from "lodash/merge" in TypeScript?

When using ES6, it's possible to import only a single function from a library in order to reduce the overall bundle size. For example: import merge from "lodash/merge" But in TypeScript, the statement above can trigger a compile error: Cannot find m ...

Angular removing every query string parameters

Linked to but distinct from: How to maintain query string parameters in URL when accessing a route of an Angular 2 app? I am facing an issue with my basic Angular application where adding a query parameter results in its removal, both from the browser&apo ...

Injecting a service into a parent class in Angular 6 without the need to pass it through the constructor

Can anyone provide guidance on how to incorporate a service with multiple dependencies into an abstract class that will be inherited by several classes, in a more streamlined manner than passing it through all constructors? I attempted to utilize static m ...

Executing TypeScript Mocha test cases using ES6 modules

Setting up mocha tests for the TypeScript App in my Rails application has been a bit of a challenge. Initially, I added a basic test to kick things off, but encountered the following error: /home/bernhard/Programs/ruby/cube_trainer/jstests/utils/optional. ...

Firebase - Accessing data for a specific item

Apologies for the lengthy question. I have a collection of events that I retrieve like this: export class HomePageComponent implements OnInit { events: FirebaseListObservable<EventModel[]>; constructor( private authService: AuthService, ...

Leverage the power of Angular's library dependency injection with the @inject

I am currently working on a project that involves a library. Within one of the classes in this library, I am attempting to provide a service using @optional, @host, and @inject decorators with an injection token. In the parent component, I have the optio ...

What is the method for filtering out specific fields in a template string?

I am currently working on defining constraints for the method field type event = { [k: `on${string}`]:(e:string)=>void } However, I need the event argument to be a number for fields that do not begin with 'on' type event = { [k: ` ...

Top method for dynamically loading a specific component by using its selector as a variable

I'm currently in the process of developing a straightforward game using Angular. The game is structured to consist of multiple rounds, each with unique characteristics that are distinguished by the variable roundType. For instance, round types can in ...

The TypeOrm many-to-one relationship with a multiple column join is giving an error: The column mentioned in the reference, <column name>, was not found in the entity <entity name>

I have an entity called A with a composite primary key, and another entity called B that has foreign keys referencing both columns of entity A. I am currently attempting to establish a many-to-one relationship between entity B (many) and entity A (one). U ...

Retrieving data from a child node using Jsonpath

Displayed below is a sample of JSON input data: { "India":{ "Attributes":{"Time":"2006-05-04T03:22:11.499Z"}, "ActiveCity":{ "profile":"Mumbai" }, "CurrentCities":{ "Mumbai":{"population":"121212121","Are ...

Is it possible to remove tsconfig.spec.json from an Angular project?

I recently started learning Angular and was introduced to the files tsconfig.app.json and tsconfig.spec.json when setting up an Angular app using Angular-CLI. I found a helpful point about these files on this website. Both tsconfig.*.json files serve as ...

The JSX component cannot be utilized as `ToastContainer`

Check out this Code: import axios from "axios"; import React, { useState, useEffect } from "react"; import { ToastContainer, toast } from "react-toastify"; import loaderIcon from "../../assets/images/loader.gif"; imp ...

Verify if a section of an arc intersects with a circular shape

I'm currently working on determining the intersection between an arc and a circle. I have successfully identified intersections when I treat the arc as a complete circle using the code snippet provided. However, I am facing difficulty in finding a so ...

Troubleshooting: Issues with importing Less files in TypeScript using Webpack and css-loader

I am currently working on a test project using TypeScript and Webpack. I have an index.ts file and a base.less (or base.css) file imported in the index.ts, but I am experiencing errors with the css-loader. Interestingly, everything works fine when the LESS ...

Unexpected behavior observed with Angular Toggle Button functionality

Having trouble implementing toggle functionality in Angular where different text is displayed when a button is toggled. I keep getting an error in my code, can anyone assist? See the code below: HTML <tr> <td>Otto</td> <td> ...

unable to assign an array to a different array in typescript

I'm facing an issue with assigning values to the private kitems array in my class. Despite defining it as kitems:any[], when I try to assign a value using this.kitems = items; and then log this.kitems, it shows up as an empty array. createprofile() { ...

The Angular Progressive Web App functions properly in ng serve mode, but encounters issues when running with http-server

I'm developing a Progressive Web App (PWA) using Angular. Everything was functioning smoothly until out of nowhere, I started encountering a 404 Error whenever I tried to navigate to a new component while serving in dist/project with http-server. Surp ...

I continue encountering the Server Error message: "Error: The default export on page "/products/all" is not a React Component."

I have been trying to create a page to display all the products listed in my server.json file (shown below). { "products": [ { "slug": "live-by-the-sun-love-by-the-moon", "title": "Live by the sun, love by the moon.", "price" ...

Understanding Vue.js - encountering the error message "property or method is not defined"

Recently, I've come across an issue that seems to be common among many people, but for some reason, I am unable to find a solution despite looking at similar questions. The problem arises when I use a v-for in a Vue Component and the array value cons ...

Failure to nest interfaces in Angular when mapping JSON responses

After calling my ASP.NET Core Web API, the JSON response appears as: [ { "driver": { "firstName": "TEST", "lastName": "LAST", "assignedRoute": "O_ROUTE" } }, { "driver": { "firstName": "First", "lastName": " ...