How can you type a collection of initialized class instances in Typescript when given an object containing classes?

Imagine having an object that resembles the following:

const typeMap = {category1: Category1, category2: Category2}

In this case, Category1 and Category2 refer to classes, and there could potentially be hundreds of different categories.

Now I also have a dynamically generated object that matches up with this structure:

const instanceMap = {category1: new typeMap.category1(), category2: new typeMap.category2()}

The challenge arises when attempting to assign types to this instanceMap since it is created dynamically.

Using the standard "typeof typeMap" method doesn't provide accurate results. Even though I access instanceMap.category1, the methods belonging to Category1 aren't visible in the auto-complete suggestions. It appears that the typeof operator treats it as typeof CategoryX, leading to the loss of visibility for all associated methods.

Answer №1

To create a mapped type utilizing the properties of classMap, you can use the InstanceType<T> utility type for each property value:

const classMap = { service1: Service1, service2: Service2 };
type ClassMap = typeof classMap;
type InstanceMap = { [K in keyof ClassMap]: InstanceType<ClassMap[K]> };

This is essentially equivalent to

/* type InstanceMap = {
    service1: Service1;
    service2: Service2;
} */

You can then assign this type to annotate the variable instanceMap without any errors:

const instanceMap: InstanceMap = {
    service1: new classMap.service1(),
    service2: new classMap.service2()
}; // ok

If you need to generate instanceMap dynamically, you will need mapped types within your function and utilize type assertions during implementation, as the compiler may not be able to deduce the logic. For example:

function makeInstanceMap<T extends Record<keyof T, object>>(
    classMap: { [K in keyof T]: new () => T[K] }): T {
    return Object.fromEntries(
        Object.entries(classMap).map(([k, v]) => [k, new (v as any)()])
    ) as T;
}

const instanceMap = makeInstanceMap(classMap);
/* const instanceMap: {
    service1: Service1;
    service2: Service2;
} */

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

Angular 7 throwing errors of undefined variables

I encountered an error message that says Property 'country' does not exist on type 'ViewComponent'. Did you mean 'country$'? I'm at a loss on how to resolve this issue. I understand that there is an undefined variable ca ...

Client-side condition handling in Angular 2

How can I change the icon image on a block/unblock button based on the user's active status? For example, showing an unlock image when the user is active and vice versa. Image https://i.stack.imgur.com/aM0ff.png Html <link href="../../font-aw ...

Personalized prefix for Angular and WebStorm components

After starting a project in Angular with Visual Studio Code a few months ago, I decided to switch to WebStorm and upgraded the project to Angular 4.0 today. Although my project is running smoothly without any errors, I encountered an issue in WebStorm: ...

Is it possible to utilize [key:string]: any in order to eliminate the requirement for an additional function when working

Currently, I am utilizing recompose within my React project. Specifically, I am leveraging its compose function which is defined as: function compose<TInner, TOutter>( ...functions: Function[] ): ComponentEnhancer<TInner, TOutter>; interf ...

Challenge with Updating React Components When Switching Themes

In my React application, I'm facing a challenge with theme switching. There are two themes available: Theme One and Theme Two. To dynamically load theme components, lazy loading has been implemented based on the selected theme. Each theme has its own ...

Have I repeated myself in defining my class properties?

Currently, I'm enhancing my understanding of Typescript with the development of a discord.js bot. However, I have come across a piece of code and I am uncertain about its redundancy: import Discord from 'discord.js'; export default class B ...

What is the best way to retrieve a property from a conditional type using generics?

The code snippet above presents an issue in TypeScript: const exampleFn = function<AttributeName extends 'attributeA' | 'attributeB'>( whatToProcess: AttributeName extends 'attributeA' ? {attributeA: string} : {attri ...

The FaceBook SDK in React Native is providing an incorrect signature when trying to retrieve a token for iOS

After successfully implementing the latest Facebook SDK react-native-fbsdk-next for Android, I am facing issues with its functionality on IOS. I have managed to obtain a token, but when attempting to use it to fetch pages, I keep getting a "wrong signature ...

angular primeng table has a checkbox to select all checkboxes

Is there a way to check all checkboxes in a table when the checkbox in the table header is clicked? I am currently utilizing angular 12 and primeNG table for this functionality. <p-table styleClass="text-sm" [value]="value" [loading] ...

Angular2 allows for the firing of all columns in one click using *ngFor

<tr *ngFor = 'let student of students> <td contenteditable="true" class ='phone' #button> {{student.phone}} <i (click)='showbox()' class = ' glyphicon glyphicon-edit'></i> <input *ngIf=&apo ...

Modify the data type of an object member based on its original type

I am seeking to convert the data type of each member in an object based on the specific member variable. Here is an example: class A { fct = (): string => 'blabla'; } class B { fct = (): number => 1; } class C { fct = (): { o ...

Discovering the functionality of es6 object.assign and find methods within a typescript file

Currently, I am in the process of transitioning from Java Script to TypeScript for my project. However, I am facing limitations as I am unable to utilize object.assign() and find methods. ...

What are the steps to incorporate SignalR into a TypeScript project?

Working on an asp.net mvc 4.5 project with typescript in the client side, I successfully installed and configured signalR on the server side. To integrate it into my project, I also installed signalr.TypeScript.DefinitelyTyped with jquery. In my typescrip ...

Difficulty locating the module in Typescript/Javascript

Currently facing an issue while trying to incorporate a module called "request" into my Angular 2 Typescript project from here. Despite following the usual installation process with npm install --save request and also attempting typings install request -- ...

Automatic type inference for TypeScript getters

It appears that Typescript infers field types based solely on the private variable of a field, rather than taking into account the getter's return type union (1) or inferring from the getter itself (2): test('field type inference', () =& ...

Ways to retrieve the key of an enum based on its value within Typescript

Here's an example of an enum: export enum Colors { RED = "RED COLOR", BLUE = "BLUE COLOR", GREEN = "GREEN COLOR" } Can you help me figure out how to retrieve the enum key based on a specific value? For instance, if I input "BLUE COLOR", ...

Retrieve the :id parameter from the URL as a numerical value in Node.js using Typescript

Is there a way to directly get the :id param from the URL as a number instead of a string in order to easily pass it on to TypeORM for fetching data based on a specific ID? Currently, I am using the following approach where I have to create an additional ...

Passing a value from an HTML template to a method within an Angular 4 component

Encountering an issue with Angular 4. HTML template markup includes a button: <td><a class="btn btn-danger" (click)="delete()"><i class="fa fa-trash"></i></a></td> Data is assigned to each td from a *ngFor, like {{ da ...

Guide to successfully passing a function as a prop to a child component and invoking it within Vue

Is it really not recommended to pass a function as a prop to a child component in Vue? If I were to attempt this, how could I achieve it? Here is my current approach: Within my child component - <template> <b-card :style="{'overflow-y&apo ...

Universal Angular along with Window's Innerwidth

Utilizing Window.Innerwidth in my Angular Project has been successful, however, I encountered an issue when attempting to implement it into Angular Universal. The content within window.innerwidth does not appear in the view source. Here is a snippet of my ...