Copying properties from object A to a new object B that extends A using TypeScript used to work on older versions of the language, but now it seems to be broken

In my scenario, I have a class B that is an extension of class A. My intention is to duplicate all the properties of class A onto class B, considering that B already has all the properties (and more) present in A.

For instance:

class TypeA {
    propX: number = 0;
    propY: number = 0;
}

class TypeB extends TypeA {
    propZ: number = 0;
}

let A: TypeA = {propX: 1, propY: 2};
let B: TypeB = new TypeB();

//I aim to copy the properties of A onto B at this point
Object.keys(A).forEach(prop => B[prop] = A[prop]); 

//now assign a value to the unique property of B
B.propZ = 3;

//expected result {propX: 1, propY: 2, propZ: 3}
console.log(B);

The line Ojbect.keys(A) ... was functional in a previous TypeScript version, but it now fails to compile. Even though it works well in this TypeScript playground, errors are encountered on that specific line. Moreover, in my Angular project, compilation is unsuccessful.

What would be the most appropriate way to achieve this now?

I did come across a similar question, although none of the suggested solutions seemed effective. While I couldn't fully comprehend the accepted "solution," I attempted to implement it in my code as follows:

let key: keyof TypeA;
for (key in A) {
  A = {
    ...A,
    [key]: B[key]
  }
}

Although this approach seems confusing to me, I gave it a shot before seeking assistance 🤷‍♂️

Your insights and guidance are greatly appreciated.

Answer №1

When you tell the compiler: "Hey, be quiet, I know what I'm doing."

Object.keys(objA).forEach((key) => { (objB as any)[key] = (objA as any)[key]; });

or

Object.keys(objA).forEach((key) => { (<any>objB)[key] = (<any>objA)[key]; });

Some may argue that it's not best practice, but in this specific scenario, I believe it works just fine.

Answer №2

If you want to securely store your access keys, one method is to keep them in a read-only array and then iterate through the keys whenever you need to copy their values. This technique can also be used to define the shape of the base class:

Try out TypeScript Playground

// Store common keys in an array that cannot be modified:
const keysArray = ['key1', 'key2'] as const;
type KeyType = typeof keysArray[number];

// Utilize the "implements" keyword when defining the base class to enforce
// that its structure conforms to the keys specified above:
class BaseClass implements Record<KeyType, number> {
  key1: number = 0;
  key2: number = 0;
}

class SubClass extends BaseClass {
  key3: number = 0;
}

let instanceA: BaseClass = {key1: 1, key2: 2};
// Note: instanceA is not an instance of BaseClass since it was not instantiated using the constructor:
console.log({'instanceA instanceof BaseClass': instanceA instanceof BaseClass}); // false

let instanceB: SubClass = new SubClass();

// Assigning values from instanceA to instanceB based on the keys in the readonly array:
for (const key of keysArray) instanceB[key] = instanceA[key];

instanceB.key3 = 3;

console.log({instanceB}); // { key1: 1, key2: 2, key3: 3 }

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

Generating observables from form submission event

Note: I am completely new to Angular and RXJS. Currently, I am working on a simple form where I want to create an observable. The goal is to listen for submit events and update a value within the component. However, I keep encountering an error message sa ...

Angular 7: Separate Views for Search Bar and Results

Two components have been developed: search-bar.component.ts: displayed in all views search.component.ts: responsible for displaying the results (response from a REST API) The functionality is as follows: whenever I need to perform a global search (produ ...

Modify the directory attribute based on a constantly changing variable

I need to adjust the dir attribute based on a variable that changes dynamically. <input [id]="'element'+i" [(ngModel)]="parent.firstName" class="form-control input-lg" ...

Ensuring the correct limitation of Records within a generic function

I am currently working on defining a generic TypeScript function that can accept a Record<number, boolean> and return the same value. The challenge I am facing is ensuring that the input type remains generic and is reflected accurately in the output. ...

Tracking the chosen columns in Devexpress ColumnChooser while navigating with Angular

In a specific situation, users can utilize the column chooser to hide/show columns, navigate away from the page, and return later only to find that the previously hidden columns remain hidden. My initial idea was to create a service that would control the ...

What is the best way to send ServerSideProps to a different page in Next.js using TypeScript?

import type { NextPage } from 'next' import Head from 'next/head' import Feed from './components/Feed'; import News from './components/News'; import Link from 'next/link'; import axios from 'axios&apo ...

What could be the reason for the unavailability of this.state in this particular situation?

In my component, I have defined the following functions: constructor(MyProps: Readonly<MyProps>){ super(MyProps); this.state = {suppliers: [], supplierId:0, supplierName:''}; this.addSupplier.bind(this); } addSupplier(){ ...

Can an Angular application be developed without the use of the app-root tag in the index.html file?

I'm a newcomer to Angular and I'm trying to wrap my head around how it functions. For example, if I have a component named "login", how can I make Angular render it directly? When I try to replace the app-root tag with app-login in index.html, n ...

Unable to install Typescript using npm

I recently started a tutorial on Typescript and wanted to install it globally using npm. npm i typescript -g However, I encountered an issue where the installation gets stuck on the first line and displays the following message: (⠂⠂⠂⠂⠂⠂⠂⠂ ...

tips for extracting nested JSON data using TypeScript

I need assistance in extracting the state parameter values for each id - 2434,78657 using typescript. Due to the nested JSON structure, I am encountering difficulties in fetching these values. JSON Request: { ...

The css property of *ngContainerOutlet is ineffective when applied to an ng-component with encapsulation

When I utilize *ngContainerOutlet to dynamically insert components, it wraps the component's template within an ng-component tag which causes my CSS styles to become ineffective. For example: <div class="my-class"> <ng-container *ngComp ...

javascript/typescript - conditionally adding an item to an object

If I have an object called userData = {..} and I need to create another object, userDataB, with properties a, b, c, and d from userData but only if they are defined. One way to achieve this is by using the following approach: userDataB = {} if(userData.a ...

Parsing a JSON array using Moment.js within a subscription function

I have a series of time entries within a data JSON array that I need to parse and format using Moment.js. The formatted data will then be stored in the this.appointmentTimes array for easy access on my view using {{appointmentTime.time}}. Here is the JSON ...

Assign Monday as the selected day of the week in the MUI Datepicker 6

I am currently using version 6 of the material ui Datepicker and I am trying to configure it so that the week starts on Monday. import React from "react"; import { DatePicker as DatePickerDestop } from "@mui/x-date-pickers/DatePicker"; ...

TypeScript error: Attempting to call a function on a potentially undefined object

Hello, I am new to TypeScript React and currently learning how to build applications using TypeScript with tutorials from YouTube. const RegisterCustomer: React.FC = () => { const [text, setText] = useState<string>(''); const [e ...

How can you define a generic type alias in TypeScript for a function that is also generic?

I am facing a challenge with creating a generic alias for a typed generic function. Despite my efforts, I have not been successful in achieving this. Here is an example of what I'm encountering: // foo.tsx function foo<T>(arg: T): T { return a ...

Using the RabbitMQ consume method in conjunction with the channel.ack function

I'm currently working on a function in TypeScript to consume messages from my RabbitMQ: async consume( queue: string, callback: (message: ConsumeMessage | null) => void, ) { return this.channel.consume(queue, message => { c ...

Token in Angular 7 returns as undefined post-login, causing potential authentication issues

Currently working on a method to retrieve the Token value and maintain user login status until they manually sign out. I am facing an issue where attempting to save it in a variable returns 'undefined', even though I can view the token value thro ...

Angular 2 directives and modules: a guide to using these powerful features

In the past, when working with older versions of Angular 2, I was able to import directives like import {CounterDirective} from './counter.directive'; and utilize them in my projects. However, with the introduction of the new App Module, I hav ...

Group data by two fields with distinct values in MongoDB

I have developed a Typescript Node.js application and I am looking to organize documents by two fields, "one_id" and "two_id", based on a specific "one_id" value. Below is the data within my collection: { "_id":"5a8b2953007a1922f00124fd", "one_id ...