What is the procedure for including a attribute in all sub-objects within a nested object using Typescript?

I need to create a function called addId that takes an object as input and returns the same object with an added property _id: string in every sub-object.

Let's consider the input object constructed from the following class.

class A {
  a: number
  b: { bb: number }
  c: number[]

  constructor() {
    this.a = 1
    this.b = { bb: 2 }
    this.c = [1,2,3]
  }
}
const a = new A()

If we run addId(a) on this object, the function would return

A {
  _id: 'id1'
  a: 1
  b: { bb: 2, _id: 'id2' }
  c: [1,2,3]
}

The parameter for addId can be an object of any class, not necessarily the class A. It can be constructed recursively from json, objects, and arrays with any nesting depth.

I am not looking for the implementation of addId, just the expected return type. I believe the solutions will involve similar techniques to those used for the type DeepReadonly<T> defined in this GitHub repository.

Answer №1

How about:

type Intelligent<T> =
  T extends Function ? T :
  T extends object ? (
    { [K in keyof T]: Intelligent<T[K]> } &
    (T extends readonly any[] ? unknown : { _id: string })
  ) : T

If T is a non-function object, it's best to recursively traverse through it and apply Intelligent<T> to each property. This approach works well for both arrays and regular objects. However, only non-array objects should have the _id property added, hence the check for T extends readonly any[]. You can verify the expected output as shown below:

declare class A {
  a: number
  b: { bb: number }
  c: number[]
}
type IntelligentA = Intelligent<A>;
/*
type IntelligentA = {
    a: number;
    b: {
        bb: number;
    } & {
        _id: string;
    };
    c: number[];
} & {
    _id: string;
}
*/

Playground link to code

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

Incorporating a new attribute into the JQueryStatic interface

I am trying to enhance the JQueryStatic interface by adding a new property called someString, which I intend to access using $.someString. Within my index.ts file, I have defined the following code: interface JQueryStatic { someString: string; } $.s ...

DateAdapter not found within Angular/Material/Datepicker - Provider not available

I need assistance with: angular / material / datepicker. My test project is running smoothly and consists of the following files: /src/app/app.module.ts import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from ' ...

Restricting types through property union types

I'm currently in the process of refining a type to a specific variant within a type, but I am encountering difficulties in accurately defining the correct type. At this moment, my type Item has the potential for having various types for its details. t ...

Observable doesn't respond to lazy loaded module subscriptions

I am trying to understand why my lazy loaded module, which loads the test component, does not allow the test component to subscribe to an observable injected by a test service. index.ts export { TestComponent } from './test.component'; export { ...

Utilize TypeScript File array within the image tag in HTML with Angular 2

I am in the process of developing a web application that allows users to upload CSV data and images, which are then displayed on the application. However, I have encountered an issue where I am unable to display the imported images. The images are imported ...

Is there a way to use Jest spyOn to monitor a function that is returned by another function?

I'm curious about why the final assertion (expect(msgSpy).toBeCalled()) in this code snippet is failing. What adjustments should be made to ensure it passes? it('spyOn test', () => { const newClient = () => { const getMsg = ...

What could be causing my Page to not update when the Context changes?

In my Base Context, I store essential information like the current logged-in user. I have a User Page that should display this information but fails to re-render when the Context changes. Initially, the Context is empty (isLoaded = false). Once the init fu ...

Is there a way to retrieve a data type from a class in TypeScript?

Within my code, there exists a class: class Person { name: string; age: number; gender: string; constructor(params: any){ this.name = params.name; this.age = params.age; this.gender = params.gender; } } My question is how ca ...

DuplicateModelError: Unable to duplicate model after it has been compiled, React.js, MongoDB, TypeScript

In the early stages of developing an application using Next.js, Mongoose, and Typescript, I encountered a persistent issue. Whenever I attempt to send a request through Postman after clicking save, it fails, displaying the error message: OverwriteModelErr ...

CLI package enables exporting API facilities

I have a mono repository containing a CLI package (packages/cli) and a web application (apps/web). I want to utilize the public API of the CLI within the web app. The CLI package is packaged with tsup: export default defineConfig({ clean: false, dts: ...

Sending data back to a previous screen in React Native

Currently, I am facing an issue with passing parameters between two screens: HomeScreen and SavedRoutesScreen. function HomeScreen(props: { //some props route:any, navigation:any, }) { React.useEffect(() => { if (props.route.params?.defin ...

What steps can be taken to troubleshoot and resolve this specific TypeScript compilation error, as well as similar errors that may

I am struggling with this TypeScript code that contains comments and seems a bit messy: function getPlacesToStopExchange(): { our: { i: number; val: number; }[]; enemy: { i: number; val: number; }[]; //[party in 'our' | 'enemy' ]: ...

Issue with constructor including an interface

I'm facing an issue with a typescript class that has an interface implemented in the constructor parameter: interface responseObject { a: string; b: boolean; c?: boolean; } class x { a: string; b: boolean; ...

What is the most effective way to determine the data type of a value associated with a key in an interface?

In my TypeScript interface, I have defined the following structure: MyInterface { 'key1': number | string; 'key2': string; 'key3': SomeOtherInterface; } I am looking to create a new type that utilizes the properties of ...

When defining a stripe in TypeScript using process.env.STRIPE_SECRET_KEY, an error of "string | undefined" is encountered

Every time I attempt to create a new stripe object, I encounter the error message "Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string& ...

What is the appropriate directory to place the `typescript` package in order for WebStorm to recognize it?

According to the information on this webpage: The Configure TypeScript Compiler dialog box provides two options: Detect: WebStorm will look for a typescript package within the current project. If it finds one, it will use that package. Otherwise ...

A generic function in Typescript that can accept an object with the first argument as a specified key

I am looking to create a function that will take a string as its first argument and will only accept a second argument of type object if it contains the first argument as a key with a boolean value: const checkFlag = (str:string, obj) => obj[str] Alth ...

Creating a blueprint for an object that inherits from another interface

I am looking to create an interface that includes unknown properties for one object, while also extending it with known properties from another interface. Here is my attempt: public async dispatchMessage(): Promise<{} extends IHasResponseFormat> I ...

Enhancing connected components in typescript with the redux dispatch method

When developing a connected component in TypeScript, I encountered an interesting design question. The issue arises with modal components, which are somewhat unique in that they are part of the DOM and are only shown or hidden. This poses a challenge where ...

What are the best ways to incorporate a theme into your ReactJS project?

Looking to create a context for applying dark or light themes in repositories without the need for any manual theme change buttons. The goal is to simply set the theme and leave it as is. Currently, I have a context setup like this: import { createContext ...