Exploring the depths of a TypeScript interface with unknown levels of complexity

My current challenge involves a recursive function that operates on an object with a generic interface. This function essentially traverses the object and creates a new one with a nearly identical interface, except for the leaf nodes which are transformed into numbers. Even though the function successfully generates this new object, I am struggling to properly assign the correct type to it.

For example:

interface IOriginal
{
    prop1: string,
    prop2: number,
    prop3: {
        prop1: boolean,
        prop2: {
            prop1: number
        },
        prop3: string
    }
}

const input : IOriginal = {
    prop1: "somestring",
    prop2: 5,
    prop3: {
        prop1: true,
        prop2: {
            prop1: 2
        },
        prop3: "otherstring"
    }
}

function traverse<T>(obj: T)
{
    /* ... map the object ... */
    return mappedObj
}

const output = traverse(input)

The desired interface of the output (mapped object) should be as follows:

interface IOutput
{
    prop1: number,
    prop2: number,
    prop3: {
        prop1: number,
        prop2: {
            prop1: number
        },
        prop3: number
    }
}

I have found that using mapped types only allows me to manipulate the first level of depth, if my explanation makes sense.

Answer №1

If you want to convert primitives to numbers and recursively map objects, you can use conditional types like this:

type ConvertToNumbers<T> = 
    T extends string | number | boolean  ? number :  
    { [ K in keyof T] : T[K] extends (infer U)[] ? ConvertToNumbers<U>[] : ConvertToNumbers<T[K]> }; 

function processObject<T>(obj: T) : ConvertToNumbers<T>
{
    /* ... mapping logic goes here ... */
    return null as any;
}
let originalObj: IOriginal;
let modifiedObj = processObject(originalObj);
modifiedObj.prop1 // will be a number
modifiedObj.prop3.prop1 // also will be a number

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

Skimming through the dictionary without iterating through every entry

Essentially, I am working with an API that contains multiple dictionaries/arrays. () When attempting to retrieve financial information for technology companies from the API (sector = technology and statement = income), Python should return 614 technology c ...

Is there a way to implement retry functionality with a delay in RxJs without resorting to the outdated retryWhen method?

I'd like to implement a retry mechanism for an observable chain with a delay of 2 seconds. While researching, I found some solutions using retryWhen. However, it appears that retryWhen is deprecated and I prefer not to use it. The retry with delay s ...

Learn how to creatively style buttons with dynamic effects using tailwindcss

My Desired Button: I have a Button component that can accept a variant prop. My goal is to have the button's className change dynamically based on the prop passed to it. Instead of using if/else statements for different buttons, I want to use a sing ...

What are the steps to execute jest in an AWS Lambda environment?

I'm looking to execute my end-to-end test post-deployment for the ability to revert in case of any issues. I've followed the guidelines outlined in this particular blog post. Below is my lambda function: export async function testLambda(event: A ...

Angular Reactive Forms - Adding Values Dynamically

I have encountered an issue while working with a reactive form. I am able to append text or files from the form in order to make an http post request successfully. However, I am unsure about how to properly append values like dates, booleans, or arrays. a ...

Conceal the React button once it has been pressed

In my checklist of questions, I have set up a system where the first button is shown if any checkboxes are selected. If no checkbox is selected, then the second "Submit" button is displayed. Upon clicking submit, a message appears inside. Additionally, for ...

Retrieve information and transform it into a dynamic variable using Firebase

I am trying to retrieve data from the current user, specifically their company named "ZeroMax", and then store this data in a global variable. The purpose of this variable is to define the path for Firebase. I believe my code gives a clear understanding of ...

How do I set up middleware with async/await in NestJS?

I am currently integrating bull-arena into my NestJS application. export class AppModule { configure(consumer: MiddlewareConsumer) { const queues = this.createArenaQueues(); const arena = Arena({ queues }, { disableListen: true }); consumer. ...

Javascript's callback mechanism allows functions to be passed as arguments

I am currently delving into the intricacies of the callback mechanism in javascript, particularly typescript. If I have a function that expects a callback as an input argument, do I need to explicitly use a return statement to connect it with the actual ca ...

Preventing Redundancy in Angular 2: Tips for Avoiding Duplicate Methods

Is there a way I can streamline my if/else statement to avoid code repetition in my header component? Take a look at the example below: export class HeaderMainComponent { logoAlt = 'We Craft beautiful websites'; // Logo alt and title texts @Vie ...

Ways to circumvent ng switch and create a component based on type

In my current code, I have an array called resourceTypes and I am using ngSwitch to create different components/directives based on the TypeName. However, I find this approach cumbersome as I have to update the code every time I add a new resource editor. ...

What is the process for creating a Deep Copy of an object in Angular?

I have a specific entity class defined as follows: export class Contact { id: number; firstName: string; lastName: string; constructor(id?, firstName?, lastName?) { this.id = id; this.firstName = firstName; this.lastName = lastName; ...

What reasons make an operator== inadequate for an std::unordered_map in C++?

What is the purpose of implementing both the == operator and a random operator that returns a size_t? Additionally, what should be the return value of the method that returns size_t? UPDATE: Clarification - When referring to the random operator, I want to ...

What is the best way to exclude multiple properties from an object in JavaScript?

Having two methods that return Pick<T, K> and Omit<T, K> types where Omit is defined as type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>, I am facing difficulty in removing multiple properties from an object. Th ...

What are the reasons behind memory leaks and decreased rendering speed when I exit and then reopen a React component (specifically Material-Table)?

I have been working on a basic React example for learning purposes, and I incorporated the use of material-table in one of my components. However, I noticed that each time I change pages and reopen the component (unmount and mount), the rendering speed of ...

Exploring Realtime Database Querying with Firebase 5.0

I'm struggling to retrieve all the data from my RTD and store it in an array for iteration. The code below is returning 'undefined'. What could be the issue? export class AppComponent { cuisines$: Observable<any[]>; cuisines: any[ ...

Inheriting an Angular 5 class with injected dependencies

I recently defined a new class @Injectable FooService { constructor(private _bar:BarService){ } } Then I decided to extend it in the following way @Injectable ExtFooService extends FooService { constructor(private _bar:BarService){ ...

Having trouble retrieving data from a behavior subject while using switchMap and refreshing in RxJS

app.component.ts import { Component, OnInit } from '@angular/core'; import { of } from 'rxjs'; import { TestService } from './test.service'; @Component({ selector: 'app-root', templateUrl: './app.component. ...

When using TypeScript with Jest or Mocha, an issue arises where the testing frameworks are unable to read JavaScript dependencies properly, resulting in an error message saying "unexpected token

Currently, I am conducting testing on a TypeScript file using Mocha. Within the file, there is a dependency that I access via the import statement, and the function I need to test resides within the same file as shown below: import { Foo } from 'foo- ...

Error encountered during Typescript compilation: The attribute 'raw' is not found within the context of the entity 'e' in express

In many instances, I have noticed that people use express.raw() or express.raw({type: 'application/json'}) as middleware in their requests... but is .raw() a legitimate method in Express? I am currently working with TypeScript and using Express ...