What is the best way to create a merge class function that can handle an unlimited number of class arguments in Typescript?

I've developed a mergeClass function that merges properties from multiple classes into one variable instance. Currently, the function requires three classes to be merged, but I'm looking for a way to allow any number of classes to be merged together. Is this even possible? If not, please let me know. Thanks.

type Constructable = new (...args: any[]) => any;

const mergeClasses = <S extends Constructable, T extends Constructable, P extends Constructable>(class1: S, class2: T, class3: P) =>
    <Si extends InstanceType<S> = InstanceType<S>, 
    Ti extends InstanceType<T> = InstanceType<T>,
    Pi extends InstanceType<P> = InstanceType<P>>
    (args1: ConstructorParameters<S>, args2: ConstructorParameters<T>, args3: ConstructorParameters<P>): Si & Ti & Pi => {
        const obj1 = new class1(...args1);
        const obj2 = new class2(...args2);
        const obj3 = new class3(...args3);
        for (const p in obj2) {
            obj1[p] = obj2[p];
        }
        for(const p in obj3){
            obj1[p] = obj3[p];
        }
        return obj1 as Si & Ti & Pi;
};

//Is it possible to do something like this in my mergeClasses function?
for(let i = 0; i<classes.length; i++){
   let obj = classes[i]
   const obj1 = new obj();
   for (const p in obj) {
     obj1[p] = obj[p];
   } 
}

const mergeE = mergeClasses(B, C, D);
const e = mergeE<B, C, D>([], [], []);

Check out the MergeClasses Function in TypeScript Playground

I know this question may receive some criticism, and that's okay. If you have an answer or insights on whether achieving this task is feasible, feel free to share your thoughts. Your feedback is valuable. Thank you!

Answer №1

Your mergeClasses function is currently limited because it uses a generic to describe each individual class. To enhance its flexibility and allow it to accept any number of classes, we can utilize a single generic parameter C to represent a tuple type of constructors.

const mergeClasses = <C extends Constructable[]>(...classes: C) =>

To extract the types for the argument arrays, we need to employ a mapped type on the tuple.

Furthermore, to determine the type for the combined instance, we utilize another mapped type to retrieve a tuple of all instances. By indexing with [number], we obtain a union of all instance types. We can leverage @jcalz's renowned UnionToIntersection utility type to convert this into an intersection of instance types.

// Include example mapped and utility types here

Check out the Typescript Playground Link for more details


The current format of accepting arguments as ([], [], []) might not be ideal, especially when dealing with multiple empty arrays. It could be cumbersome to switch to a single ...args format while ensuring that the correct arguments are passed to the corresponding constructors if they require varying argument counts.

If your classes don't require any arguments, you can optimize the code by simplifying the argument passing process.

// Code snippet for handling classes with no arguments

View the updated version on Typescript Playground


An alternative approach is to mandate that all classes accept a single argument (a props object) and modify the merged class accordingly to receive an object containing properties (assuming there are no conflicting property types).

// Refactored code snippet to handle classes with a common props argument

Visit the Typescript Playground Link for the revised implementation

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

An unexpected token was encountered by Jest while running a test in a test.tsx file for a React Native project

It seems like many individuals are encountering this particular issue. Despite trying various methods, I am still unable to resolve it. Currently, I am facing the following error in my terminal: FAIL tests/App.test.tsx ● Test suite failed to run Jest ...

I need to compile a comprehensive inventory of all the publicly accessible attributes belonging to a Class/Interface

When working with TypeScript, one of the advantages is defining classes and their public properties. Is there a method to list all the public properties associated with a particular class? class Car { model: string; } let car:Car = new Car(); Object. ...

Are there any methods to utilize Zod for validating that a number contains a maximum of two decimal places?

How can I ensure that a numeric property in my object has only up to 2 decimal digits? For example: 1 // acceptable 1.1 // acceptable 1.11 // acceptable 1.111 // not acceptable Is there a method to achieve this? I checked Zod's documentation and sea ...

Creating an Array in TypeScript

Is it possible to declare a global array in Typescript so that it can be accessed using "this" from any part of the code? In javascript, I would typically declare it as "var anArray=[]". What is the equivalent way of doing this in Typescript? Using anArra ...

different ways to retrieve component properties without using inheritance

In order to modify certain properties of components after login, such as the "message" property of HomeComponent and the "age" property of UserComponent, I am unable to inherit the component class. What are some alternative methods to achieve this? Authen ...

Issue with Vue @Watch not properly recognizing changes in a boolean value

I'm currently experimenting with watch functions in vue-ts. I have configured a watch function that is supposed to trigger whenever a Boolean variable's value changes, but for some reason, it's not triggering at all and I'm unable to de ...

Incorrect line numbers displayed in component stack trace [TypeScript + React]

Challenge I am currently working on integrating an error boundary into my client-side React application. During development, I aim to showcase the error along with a stack trace within the browser window, similar to the error overlays found in create-reac ...

Error: Unable to locate the file "./pages/layout/Layout" in the path "src/index.tsx"

After cloning the source code from GitHub and deploying it to Azure cloud, I encountered an error when running the command "azd up." Here are the relevant portions of my code: import ReactDOM from 'react-dom/client'; import { createHashRouter, Ro ...

Using React-Bootstrap with TypeScript in your project

I'm currently working on creating a navigation bar using react-bootstrap. I've already installed the node-module as follows: "@types/react-bootstrap": "^0.32.11",. However, when I try to use it in my hello.tsx component, I encounter a compile err ...

Waiting for the function to complete within an if statement

When attempting a test, I encountered an issue where the function does not wait for the database request to be made. It seems like the function initially returns undefined, and only after the request is completed it returns true or false causing the test t ...

Registering a function for chart.js plugins that manipulates external data

Is there a way to pass external data to the chart.plugins.register function? I'm struggling because I can't access the necessary context: Chart.plugins.register( { beforeDraw: function (chart) { //implementation } }); I attempted using ...

When using JSON.stringify(), integers are transformed into exponential notation

I have a set of data [ "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", 1000000000000000000000 ], When using JSON.stringify(), it changes to: [ "5GrwvaEF5zXb26F ...

The 'XXX' property is not found in 'YYY' type but is necessary in 'ZZZ' type

I'm struggling with setting up class properties in TypeScript. Here is the TypeScript code that I am working on: export class myClass { a: number; b: number; public getCopy(anotherClass: myClass): myClass { return { a: anotherClass.a, ...

A guide on implementing radio buttons in Angular 2 and sending the selected value via a HTTP post request

As a newcomer to Angular 2, I am struggling with the following code: Here is my HTML <form action="POST" (submit)="register()" class="aa-login-form"> <input type="radio" [(ngModel)]="gender" name="sex" value="MALE"> Male <input ...

Ensuring the correct type for an object's interface property value

I am currently working on defining a new interface interface SUser { ID: number; NAME: string; MAIL: string; PASSWORD: string; GENDER: number; BIRTHDATE: string; ID_FB: string; CREDIT: number; ID_REFERRAL: number; } My objective is to c ...

Asynchronously retrieving data in .NET using Angular

Initially, I am attempting to retrieve all projects from the database based on the provided userId from the URL. This operation is performed in the ngOnInit() lifecycle hook. Each project contains a field named Languages, which represents a list of objec ...

Utilizing dual sets of typedefs within Apollo

Running a server with ApolloServer on my Node environment: // App.js const express = require('express'); const { ApolloServer } = require('apollo-server-express'); const resolvers = require('./resolvers.js'); const typeDefs = ...

I'm puzzled as to why the banner text for my three images in the slider is only displaying on one of the images, all crammed together

Currently, I am working on an ecommerce project with Next.js. One of the challenges I faced was while setting up my banner page that includes a react-slick slider for images. Initially, when I added just one image, I noticed multiple renderings of it, but ...

The maximize button mysteriously disappears in Ubuntu when using electron applications

I am encountering an issue with Ubuntu where the maximize screen button is not visible when compiling the Electron project. When I say "compile," I am referring to running electron build => ng build --configuration=dev && electron. My version of Electro ...

The production build is encountering an issue with a type error stating that the property 'companies' does not exist on the 'PrismaClient' type, while the local build is successful

Currently, I am working on a nextjs project hosted on Vercel, utilizing TypeScript and Prisma. Here are the versions I am using: "next": "13.0.3" "typescript": "4.9.3" "prisma": "^4.6.1" My local build is successful, but I am encountering a failure on Ve ...