Generating instances of class dynamically from an array in Typescript

I'm looking to dynamically instantiate components in my code, but I seem to be struggling with the implementation. Do I need to use "cast" as I understand it or is there a more elegant solution?

abstract class Component{
    abstract mount(): void;
}

class ComponentA extends Component{
    mount(){}
    send(){}
}

class ComponentB extends Component{
    mount(){}
}

type Components = {
    componentA: ComponentA,
    componentB: ComponentB
}

const componentsName = [ComponentA, ComponentB];
const instances = {} as Components;

for(const component of componentsName){
    instances[component.name] = new component(); //how to cast?
    //Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Components'.
    //No index signature with a parameter of type 'string' was found on type 'Components'.(7053)
}

function getComponent <T extends keyof Components>(componentName: T): Components[T] {
    return instances[componentName];
}

//test 1
const componentA = instances.componentA
const componentB = instances.componentB

//test 2
const componentA2 = getComponent("componentA").send //mount | send
const componentB2 = getComponent("componentB").mount //only mount

Typescript playground

Answer №1

I had to enable ES2019 support in the TypeScript playground to accommodate Object.fromEntries. I'm uncertain if this workaround meets your requirements, as it essentially involves a type-cast similar to what you previously used.

Furthermore, there was an issue in your code where the component.name of, for example, ComponentA, is "ComponentA" instead of "componentA" as desired. This has also been addressed below.

abstract class Component{
    abstract mount(): void;
}

class ComponentA extends Component{
    mount(){}
    send(){}
}

class ComponentB extends Component{
    mount(){}
}

type Components = {
    componentA: ComponentA,
    componentB: ComponentB
}

const componentsName = [ComponentA, ComponentB] as const;
const instances = Object.fromEntries(componentsName.map((component) => [component.name[0].toLowerCase() + component.name.substring(1), new component()])) as Components;

function getComponent <T extends keyof Components>(componentName: T): Components[T] {
    return instances[componentName];
}

//test 1
const componentA = instances.componentA
const componentB = instances.componentB

//test 2
const componentA2 = getComponent("componentA").send //mount | send
const componentB2 = getComponent("componentB").mount //only mount

TypeScript Playground

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

Conditional Skipping of Lines in Node Line Reader: A Step-by-Step Guide

I am currently in the process of developing a project that involves using a line reader to input credit card numbers into a validator and identifier. If I input 10 numbers from four different credit card companies, I want to filter out the numbers from thr ...

Using ng2 to retrieve an object from an HttpGet service

I'm currently facing an issue with retrieving JSON data from my WebAPI. Every time I attempt to use the returned object in my component, it displays as undefined. The goal is to showcase student and course data on the homepage of my website. Currentl ...

Watchable: Yield the outcome of a Promise as long as watching continues

I am looking to create a function in Angular and TypeScript that will return an Observable for subscription. This Observable should emit the result of a Promise every three seconds. Currently, I have a function that returns a Promise, but I need it to ret ...

Trouble with Mui theme not being applied when inside a wrapper component

In my project using React with typescript and MUI version 5.4.2, I have been attempting to manage all styles in a single file by enclosing everything inside my App.tsx component. Problem: The custom MUI theme is not being applied throughout my application ...

Methods for assigning values to a formControl using an array

I have an array of objects and I am attempting to loop through the array, dynamically setting values to a formControl and not displaying anything if the value is null. I have searched for similar solutions but haven't found any references or examples ...

Getting React, Redux, and Typescript all collaborating together

Recently, I made the transition from using Angular to learning React and Redux. My first challenge arose when trying to integrate Redux into my React project. I set up a simple state, action, reducer, and store in my index.tsx file: export interface AppSt ...

Switching languages in Angular2 i18n

Seeking a solution to dynamically set the current language for display: I have followed the latest angular recipe for internationalization as outlined here, which states "the user's language is hardcoded as a global document.locale variable in the ...

What is the best way to transfer my static files to the desired output directory in a TypeScript Express application?

I am attempting to transfer my static files from the input directory to the output directory using Express. I found guidance in this tutorial, which utilized shell.js for copying static files. The code responsible for this operation is located in CopyAsse ...

Is there a function return type that corresponds to the parameter types when the spread operator is used?

Is it possible to specify a return type for the Mixin() function below that would result in an intersection type based on the parameter types? function Mixin(...classRefs: any[]) { return merge(class {}, ...classRefs); } function merge(derived: any, ... ...

To validate any object, ensure that it contains a specific key before retrieving the corresponding value in typescript

When looking at a random object, my goal is to verify that it follows a certain structure. obj = {WHERE:{antherObject},OPTIONS{anotherObject}} Once I confirm the object has the key using hasProperty(key), how can I retrieve the value of the key? I thoug ...

Utilizing checkboxes for toggling the visibility of buttons in Angular

I want to dynamically show or hide buttons based on a checkbox. Here is the HTML code I am using: <input class="form-check-input" [(ngModel)]="switchCase" type="checkbox" id="flexSwitchCheckChecked" (change)=" ...

Can content projection be utilized from a child component in Angular?

Keep in mind, this example could be achieved without using content projection. I am just showing a simplified version here. Imagine having a component that displays lists of names in two separate elements: import { Component } from '@angular/core&ap ...

Is Typescript reliable when working with a reference to a DOM element?

In this scenario, a function is provided with the task of obtaining a reference to a DOM element and executing certain actions: function getElementAndDoStuff() { // element: HTMLElement | null const element = document.getElementById('id'); ...

How to create a Typescript function with a void return type that accepts any arguments

I am trying to create a decorator function that takes another function as an argument: type SomeType = ??? => void; const decorate = (fn: SomeType): SomeType => { ... } How can I define the "SomeType" type in a way that restricts the decorate fu ...

Create an array containing the data returned from the Observable<{string, number, string}[]> stream

Currently I am working on creating an Angular 9 app, and I need to return an array with my response. Within the service class, I have a method like this: getReport(startDate: string, endDate: string) { return this.http.get<ReportReport>( ...

Restricting a checkbox to a maximum of 5 checkmarks

In a multi-column table, each column is represented by a checkmark. I want to limit the ability to tick a checkmark to only 5 checkmarks. Here is the code that has been implemented: <tbody> <ng-container *ngFor="let col of testData" ...

Separate an HTML tag along with its content at the caret position into several distinct tags

Having some issues with splitting tag contents at caret position. The spliting index and the tag contents after splitting are accessible, however, encountering a problem as described below. <html> <div contenteditable="true"> <s ...

Tips for storing an image in local storage with an angular reactive form

I'm currently working on an Angular project where my goal is to implement a feature that allows users to upload an image using an angular reactive form and then store that image in the local storage. Here is a snippet of the code from "edit.component ...

Facing a problem with querying interfaces and types in TypeScript

My goal is to pass a variable to an RTK Query API service that uses a typescript interface: const device_id: unique symbol = Symbol(props.id); const { data: device, isFetching, isLoading, } = useGetAssetsByIdQuery(device_id, { pollingInterv ...

Can you explain the concept of a type object in typescript?

Can you explain the concept of the type object and its use? Some say it's like a blackbox. Which approach is better, A or B, when dealing with a parameter that may have unknown types of object keys? A const modifyData: (data: object) => void = da ...