Employing a general-purpose function in a recursive manner

My function that removes properties from an object and returns a new one works fine, but it runs into issues when dealing with nested arrays of objects. How can I tackle this challenge?

interface User {
  id: number;
  name: string;
  items?: User[];
}

const user: User = {
  id: 1,
  name: 'test',
  items: [
    {
      id: 1,
      name: 'item',
    },
  ],
};

function adjustObject<T>(fields: (keyof T)[], obj: T): T {
  const newObject = {} as T;

  for (const key in obj) {
    if (!fields.includes(key)) {
      newObject[key] = obj[key];
    }

    if (Array.isArray(obj[key])) {
      newObject[key] = [];

      for (let j = 0; j < obj[key].length; j++) {
        newObject[key].push(adjustObject(fields, obj[key][j]));
      }
    }
  }

  return newObject;
}
const result = adjustObject(['id'], user);
console.log(result);

Try out the code on Playground

Answer №1

You're facing two challenges in this scenario.

Unfortunately, TypeScript lacks the ability to automatically recognize that newObject[key] should be of type array when obj[key] is an array. You'll have to manually specify the type since undefined[] may not always exist in type T.

newObject[key] = [] as unknown as T[typeof key];

In addition, it's not possible to check a type on an item within an array if you require that type information, as TypeScript struggles to keep track of it.

Instead of verifying if obj[key] is an array type, consider assigning this to a new variable and then performing the checks:

const val = obj[key];

if (Array.isArray(val)) {
    newObject[key] = [] as unknown as T[typeof key];
  
    for (let j = 0; j < val.length; j++) {
        newObject[key].push(transformObject(fields, obj[key][j]));
    }
}

Lastly, note that newObject[key] may not exactly be an array, so you need to explicitly define its type for TypeScript:

(newObject[key] as undefined as T[]).push(transformObject(fields, obj[key][j]));

While there could potentially be a more elegant solution involving type inference, sometimes you just have to resort to casting types—especially in situations involving generic type recursion.

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 distinguishes between the methods of detecting falsy and truthy values?

While working with JavaScript / Typescript, I often find myself needing to verify if a length exists or if a value is true or false. So, the main query arises: are there any differences in performance or behavior when checking like this... const data = [ ...

What is a way to construct an object without resorting to casts or manually declaring variables for each field?

Click here for a hands-on example. Take a look at the code snippet below: export type BigType = { foo: number; bar?: number; baz: number; qux?: string[]; }; function BuildBigType(params: string[]) { // Here's what I'd like to do: ...

Is there a way to remove the old React component when there are two instances of it still active while passing variables?

Recently, I've encountered some unusual behavior with my React component. As a newcomer to React, I have a page where users can configure toast notifications that are displayed. For this functionality, I'm utilizing the react-hot-toast package. U ...

Using NodeJS to perform asynchronous tasks with setImmediate while also incorporating private class

Today marks my first time experimenting with setImmediate. I've come to realize that it may not be able to run private class methods. Can someone shed some light on this? Why is that the case? Not Functioning Properly When trying to use a private cl ...

How can type annotations be properly incorporated into this TypeScript code using an inline function class?

How can I provide type annotations to inform TypeScript that this code is correct? Indeed, I do require that inline function class. The code presented here is a simplified version of my actual problem. let x = 10; const obj = new (function() { if(--x) r ...

How to conditionally import various modules in Next.js based on the environment

Having two modules 'web,ts' and 'node.ts' that share similar interfaces can be challenging. The former is designed to operate on the client side and edge environment, while the latter depends on node:crypto. To simplify this setup, I a ...

Error in sending data to the server via the specified URL: "Http failure response for http://localhost/post.php: 0 Unknown Error" and POST request to http://localhost/post.php failed with error code

Feeling a bit stuck trying to add data to my database. As a junior with PHP and Angular, I am using PHP via XAMPP and Angular 8. Is it possible to create separate files for the post and get methods in the PHP file? app.component.ts import { Component, O ...

Retrieve unique values based on two or more criteria from an array in TypeScript

Presented here is an array. https://i.stack.imgur.com/zHXim.png The desired pattern is: https://i.stack.imgur.com/EGUiM.png I am interested in retrieving unique "CityRef" and "City". Subsequently, locating all items associated with them. ...

Implementing Angular 2 reactive forms checkbox validation in an Ionic application

I have implemented Angular Forms to create a basic form with fields for email, password, and a checkbox for Terms&Conditions in my Ionic application. Here is the HTML code: <form [formGroup]="registerForm" (ngSubmit)="register()" class="center"> ...

Using React and TypeScript to Consume Context with Higher Order Components (HOC)

Trying to incorporate the example Consuming Context with a HOC from React's documentation (React 16.3) into TypeScript (2.8) has been quite challenging for me. Here is the snippet of code provided in the React manual: const ThemeContext = React.creat ...

ERROR UnhandledTypeError: Unable to access attributes of null (attempting to retrieve 'pipe')

When I include "{ observe: 'response' }" in my request, why do I encounter an error (ERROR TypeError: Cannot read properties of undefined (reading 'pipe'))? This is to retrieve all headers. let answer = this.http.post<ResponseLog ...

Cannot access Injectable service in Angular2

In the angular2 application, there is a service named HttpClient. The purpose of this service is to include an authorization header in every request sent by the application to endpoints. import { Injectable } from '@angular/core'; import { He ...

Utilize the power of relative import by including the complete filename

When working on my TypeScript project, I have noticed that to import ./foo/index.ts, there are four different ways to do it: import Foo from './foo' // ❌ import Foo from './foo/index' // ❌ import Foo from './foo/i ...

A destructured object with a Typescript interface

While working on a React / TypeScript project, I encountered an error involving destructuring an object. The issue arises when I try to destructure notificationData within the publish function. An error message stating "Property 'messages' does ...

Count the number of checked checkboxes by looping through ngFor in Angular

My ngFor loop generates a series of checkboxes based on the X number of items in childrenList: <div *ngFor="let child of childrenList; let indice=index"> <p-checkbox label="{{child.firstname}} {{child.lastname}}" binary=&qu ...

Encountering an error code TS5055 when attempting to call an API within a TypeScript constructor

I'm attempting to retrieve a list of customers by calling a GET API from a dashboard constructor as shown below: // tslint:disable-next-line:max-line-length constructor(public addCustomerDialog: MatDialog, private router: Router, private rout ...

Error message in Typescript: "Property cannot be assigned to because it is immutable, despite not being designated as read-only"

Here is the code snippet I am working with: type SetupProps = { defaults: string; } export class Setup extends React.Component<SetupProps, SetupState> { constructor(props: any) { super(props); this.props.defaults = "Whatever ...

Errors detected while attempting to install dependencies using pnpm: modules unspecified

I recently decided to experiment with using pnpm instead of npm for my new projects, but I've encountered an issue. Let's take my nuxt project as an example. First, I set up my project using the command: pnpx nuxi init my-project Then, I insta ...

Retrieve the text content of the <ul> <li> elements following a click on them

Currently, I am able to pass the .innerTXT of any item I click in my list of items. However, when I click on a nested item like statistics -> tests, I want to display the entire path and not just 'tests'. Can someone assist me in resolving thi ...

The Angular Observable continues to show an array instead of a single string value

The project I am working on is a bit disorganized, so I will try to explain it as simply as possible. For context, the technologies being used include Angular, Spring, and Maven. However, I believe the only relevant part is Angular. My goal is to make a c ...