creating a duplicate of a class instance in TypeScript

Struggling to replicate an instance in typescript.

Tried using jQuery.extend(true, {}, instance) but methods are not copied

Any assistance on this issue would be highly appreciated

Answer №1

To achieve a generic clone function, it is necessary for your classes to possess a default constructor:

function duplicate<T>(instance: T): T {
    const copy = new (instance.constructor as { new (): T })();
    Object.assign(copy, instance);
    return copy;
}

For instance:

class A {
    private _num: number;
    private _str: string;

    get num() {
        return this._num;
    }

    set num(value: number) {
        this._num = value;
    }

    get str() {
        return this._str;
    }

    set str(value: string) {
        this._str = value;
    }
}

let a = new A();
a.num = 3;
a.str = "string";

let b = duplicate(a);
console.log(b.num); // 3
console.log(b.str); // "string"

(view code in playground)

If your classes are more intricate (contain other class instances as members and/or lack a default constructor), then implement a duplicate method within your classes that can handle construction and assignment of values.

Answer №2

After reading @Nitzan Tomer's answer, I developed the following code to automatically replicate nested properties if they are deemed Cloneable. Nevertheless, I am uncertain of the extent to which this approach is effective and what limitations it may have;

import { isUndefined } from "lodash";

export abstract class Cloneable<T> {
  clone(newPropertyValues: Partial<T> = {}): T {
    const clone = new (this.constructor as { new (): T })();

    const nestedClones = Object.getOwnPropertyNames(clone)
      .reduce((partial, propertyName) => {
        const property = Object.getOwnPropertyDescriptor(clone, propertyName) 
        const isCloneable = property?.value instanceof Cloneable
        const isNotProvided = isUndefined(
          Object.getOwnPropertyDescriptor(newPropertyValues, propertyName)
        )
        
        if(isCloneable && isNotProvided) {
          partial[propertyName as keyof T] = property?.value.clone()
        }

        return partial
      }, {} as Partial<T>)

    return Object.assign(clone, this, nestedClones, newPropertyValues);
  }

  cloneWith(newPropertyValues: Partial<T>): T {
    return this.clone(newPropertyValues)
  } 
}

To utilize this functionality, simply inherit from Cloneable<T> and make use of the clone method along with a typed cloneWith* for overriding specific values.

*The inclusion of cloneWith is primarily for improved semantics

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 best way to integrate AWS-Amplify Auth into componentized functions?

Issue: I am encountering an error when attempting to utilize Auth from AWS-Amplify in separate functions within a componentized structure, specifically in a helper.ts file. Usage: employerID: Auth.user.attributes["custom:id"], Error Message: Pr ...

Fill a dynamic form with a date sourced from the ngrx storage

How can I populate a form with data from the store if setValue and patchValue methods are not working? export class MyComponent implements OnInit, OnDestroy { public newsletterToEdit$: Observable<NewNewsletter> = this.store.selectNewsletterToEdi ...

Comparing the cost of memory and performance between using classes and interfaces

As I delve into writing TypeScript for my Angular project, one burning question arises — should I use an Interface or a Class to create my domain objects? My quest is to uncover solid data regarding the actual implications of opting for the Class route. ...

Utilizing async/await to pass a variable instead of subscribing to it

In my attempt to utilize the async/await method for a dual API call, I encountered an issue where variables within the second async function were not functioning properly or being rendered by Angular. const pokemon = this.httpClient .get(`https://pokeapi ...

Can the data cells of columns be dynamically adjusted to align them on a single vertical line?

For some time now, I have been grappling with a CSS issue. I am working with a table that has 3 columns displaying departures, times, and situational text for scenarios like delays or cancellations. However, as evident from the images, the alignment of th ...

Initiating Angular APP_INITIALIZERThe Angular APP_INITIALIZER

I am a newcomer to Angular and currently utilizing Angular6 for development purposes. I have a specific query regarding my app. Before the app initializes, I need to invoke three services that provide configurations required by the app. Let's refer to ...

Tips for preventing repetition in http subscribe blocks across various components

Imagine a scenario where there is a service used for making HTTP request calls. There are two different components (which could be more than two) that need to send the same request using the same observables via this service. After receiving the result, it ...

Guide on importing and using types from an external library in my declaration file

Querying Library Types in a .d.ts Declaration File I am currently working on creating a custom namespace in a cf.d.ts file to define general-purpose types for my application. This allows me to avoid importing modules repeatedly whenever I need to referenc ...

How should dynamic route pages be properly managed in NextJS?

Working on my first project using NextJS, I'm curious about the proper approach to managing dynamic routing. I've set up a http://localhost:3000/trips route that shows a page with a list of cards representing different "trips": https://i.stack. ...

Changing JSON into an array with typescript

I have encountered a JSON structure that is causing me some trouble: const help = [ { "en": [ { "test2": [ { "title": "Naslov1", &quo ...

Remove the main project from the list of projects to be linted in

Currently in the process of transitioning my Angular application to NX and have successfully created some libraries. I am now looking to execute the nx affected command, such as nx affected:lint, but it is throwing an error: nx run Keira3:lint Oops! Somet ...

Disabling dynamic color updates upon refresh

I am currently using chartjs and I want to generate new random colors each time the page is refreshed. However, I need these colors to remain fixed and not change after a page refresh or reload. Below is the function I am working with: getRandomRgb() { ...

The address :::3000 is already in use by NestJS

While attempting to deploy my NestJs server on a C-Panel hosting, I have encountered an issue. Despite properly installing all node_modules and ensuring every project file is in place, the server fails to start and continuously displays the following error ...

How to dynamically insert variables into a separate HTML file while creating a VS Code extension

Currently working on a vscode extension, I'm facing an issue with containing the html in a string (like this: https://github.com/microsoft/vscode-extension-samples/blob/main/webview-view-sample/src/extension.ts). It leads to a large file size and lack ...

TypeScript in conjunction with Eslint is throwing an error stating it is unable to locate a particular

One of the modules is causing eslint complaints, even though it is installed and functioning properly in the code. Error message: Unable to resolve path to module '@azure/functions'.eslintimport/no-unresolved az/index.ts import { AzureFunction ...

Angular 2 module that is loaded lazily - service does not follow singleton pattern

After successfully implementing lazy loading modules into my application, I have ensured that the app.module.ts is properly configured. @NgModule({ declarations: [ AppComponent, HeaderComponent, HomeComponent ], imports: [ BrowserMod ...

What could be the reason for TypeScript throwing an error that 'product' does not exist in type '{...}' even though 'product' is present?

Structure of Prisma Models: model Product { id String @id @default(auto()) @map("_id") @db.ObjectId name String description String price Float image String createdAt DateTime @default(now()) updatedAt Da ...

In Typescript, the error message "Property 'content' is not found on the type 'HTMLElement'" indicates that the 'content' property is not

Whenever I attempt to access the content of a meta tag, I encounter an error: document.getElementById('mymetatag').content While this code works in Javascript, TypeScript throws an error that says: Property 'content' does not exist o ...

Optimizing and scaling Firebase for improved performance

Is it possible to efficiently retrieve schedules from a database with thousands, or even millions, of records in the future? I am planning on storing schedules from healthcare professionals in a collection, but I am unsure if it is better to store them wi ...

What is the most efficient way to iterate through an array to push properties into an object nested within another array?

I have been working on a small Angular application that functions as a scheduler, allowing users to input a Name, Start and End dates, and toggle a boolean checkbox through a form. One challenge I am facing is trying to assign the names entered by each use ...